Skip to content

Refactor task dependency graph to single-source (blockedBy only)#127

Open
JIA-ZI-LONG wants to merge 1 commit intoshareAI-lab:mainfrom
JIA-ZI-LONG:refactor/task-graph-single-source
Open

Refactor task dependency graph to single-source (blockedBy only)#127
JIA-ZI-LONG wants to merge 1 commit intoshareAI-lab:mainfrom
JIA-ZI-LONG:refactor/task-graph-single-source

Conversation

@JIA-ZI-LONG
Copy link

@JIA-ZI-LONG JIA-ZI-LONG commented Mar 24, 2026

Background

The TaskManager in s07_task_system.py maintained both blockedBy (incoming edges) and blocks (outgoing edges) for each node. The design intended that calling update() once with both add_blocked_by and add_blocks would update edges bidirectionally.

However, this design has two problems:

1. LLM never actually uses add_blocks

Debugging showed that whether creating task chains (3 creates followed by updates to connect) or inserting new nodes (A→B→C becoming A→B→D→C), the LLM always calls update() separately for each node, only passing add_blocked_by. The add_blocks parameter was never used - it's dead code.

2. Even if LLM followed the design, the graph would be incomplete

When handling add_blocks, update() syncs to the next node's blockedBy, but never updates the previous node's blocks. This means edge records are unidirectional and missing, making blocks useless for understanding the graph structure.

Conclusion

The blocks field is neither used by LLM nor can it stay consistent. It should be removed. Execution scheduling only needs blockedBy (the existing _clear_dependency also never reads blocks). Added remove_blocked_by to support edge removal when inserting nodes.

Changes

  • Remove blocks field from task creation
  • Remove add_blocks parameter from update() and its handling logic
  • Add remove_blocked_by parameter to support edge removal during graph rewrites
  • Update tool handlers and JSON schema accordingly
  • Update documentation (en/ja/zh) to reflect the changes

New Usage Example

Inserting D between B→C:

TASKS.create("D")
TASKS.update(D_id, add_blocked_by=[B_id])
TASKS.update(C_id, add_blocked_by=[D_id], remove_blocked_by=[B_id])

Test Results

Test 1: Create task chain with dependencies

s07 >> Create 3 tasks: "Setup project", "Write code", "Write tests". Make them depend on each other in order.

> task_create: {"id": 1, "subject": "Setup project", "status": "pending", "blockedBy": []}
> task_create: {"id": 2, "subject": "Write code", "status": "pending", "blockedBy": []}
> task_create: {"id": 3, "subject": "Write tests", "status": "pending", "blockedBy": []}
> task_update: {"id": 2, "blockedBy": [1]}
> task_update: {"id": 3, "blockedBy": [2]}

Task chain: Setup project → Write code → Write tests

Test 2: Insert node between existing tasks

s07 >> insert a task called Deep Thinking between task 2 and task 3

> task_create: {"id": 4, "subject": "Deep Thinking", "status": "pending", "blockedBy": []}
> task_update: {"id": 4, "blockedBy": [2]}
> task_update: {"id": 3, "blockedBy": [4]}
> task_list: 
[ ] #1: Setup project
[ ] #2: Write code (blocked by: [1])
[ ] #3: Write tests (blocked by: [4])
[ ] #4: Deep Thinking (blocked by: [2])

New flow: Setup project → Write code → Deep Thinking → Write tests

✅ LLM correctly uses add_blocked_by and remove_blocked_by to rewire the dependency graph when inserting nodes.

Test Plan

  • Run python agents/s07_task_system.py and verify the agent can still create and manage tasks
  • Test task dependency creation with add_blocked_by
  • Test edge removal with remove_blocked_by for node insertion scenarios
  • Verify task completion correctly clears dependencies

Background:
The TaskManager in s07_task_system.py maintained both `blockedBy` (incoming edges)
and `blocks` (outgoing edges) for each node. The design intended that calling
update() once with both `add_blocked_by` and `add_blocks` would update edges
bidirectionally. However, this design has two problems:

1. LLM never actually uses `add_blocks`:
   Debugging showed that whether creating task chains (3 creates followed by
   updates to connect) or inserting new nodes (A→B→C becoming A→B→D→C), the
   LLM always calls update() separately for each node, only passing
   `add_blocked_by`. The `add_blocks` parameter was never used - it's dead code.

2. Even if LLM followed the design, the graph would be incomplete:
   When handling `add_blocks`, update() syncs to the next node's `blockedBy`,
   but never updates the previous node's `blocks`. This means edge records
   are unidirectional and missing, making `blocks` useless for understanding
   the graph structure.

Conclusion: The `blocks` field is neither used by LLM nor can it stay consistent.
It should be removed. Execution scheduling only needs `blockedBy` (the existing
_clear_dependency also never reads `blocks`). Added `remove_blocked_by` to
support edge removal when inserting nodes.

Changes:
- Remove `blocks` field from task creation
- Remove `add_blocks` parameter from update() and its handling logic
- Add `remove_blocked_by` parameter to support edge removal during graph rewrites
- Update tool handlers and JSON schema accordingly
- Update documentation (en/ja/zh) to reflect the changes

New usage example (inserting D between B→C):
  TASKS.create("D")
  TASKS.update(D_id, add_blocked_by=[B_id])
  TASKS.update(C_id, add_blocked_by=[D_id], remove_blocked_by=[B_id])
@vercel
Copy link

vercel bot commented Mar 24, 2026

@JIA-ZI-LONG is attempting to deploy a commit to the crazyboym's projects Team on Vercel.

A member of the Team first needs to authorize it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant