Skip to content

🐛 fix(delegate): strip kanban toolset from delegated children - #71

Merged
cwest merged 1 commit into
cwest/integrationfrom
wt/t_3ee4fbbc
Jul 19, 2026
Merged

🐛 fix(delegate): strip kanban toolset from delegated children#71
cwest merged 1 commit into
cwest/integrationfrom
wt/t_3ee4fbbc

Conversation

@cwest

@cwest cwest commented Jul 19, 2026

Copy link
Copy Markdown
Owner

Why

A worker that spawns a delegate_task subagent can have that subagent inherit the kanban toolset. Because a delegated child also inherits the parent process's HERMES_KANBAN_TASK env, the child's end-of-run kanban_complete (called with no explicit task_id) falls back to that env var and resolves the parent's card — falsely flipping it to done with the child's summary while the real deliverable was never produced (false-done, control-surface-bleed).

What

Add "kanban" to the composite toolsets stripped from every delegated child in _strip_blocked_tools (tools/delegate_tool.py), alongside delegation and code_execution. Children get no card-terminal authority:

  • The strip is unconditional. Orchestrator children re-gain delegation by role after the strip, but there is no kanban re-add, so no delegated agent (leaf or orchestrator) ever holds the kanban terminal verbs bound to its parent's card.
  • Applies on both toolset-resolution paths — an explicitly requested toolsets=["kanban", ...] and the no-toolsets-requested inheritance of the parent's full set both route through _strip_blocked_tools.

How verified

  • Root cause traced end to end: child toolset inheritance at _build_child_agent (parent set → _strip_blocked_tools) + kanban_complete's _default_task_id fallback to HERMES_KANBAN_TASK.
  • Behavior-contract tests added in tests/tools/test_delegate_toolset_scope.py: a child never receives kanban on the explicit-request path or the inherited-set path. RED before the fix, GREEN after.
  • Targeted suites green: test_delegate_toolset_scope.py, test_delegate.py (except one pre-existing timing-sensitive heartbeat flake that passes 3/3 in isolation), test_kanban_tools.py.
  • Full suite: the remaining failures reproduce identically on the pristine base commit (a7ed14f) with this change reverted — they are pre-existing environmental/parallel-load failures, not regressions from this change.

Verified STILL BROKEN on origin/cwest/integration HEAD a7ed14f before the fix.

A delegate_task child inherits the parent's enabled toolsets AND the
parent's HERMES_KANBAN_TASK env. A child that kept the kanban toolset
could call kanban_complete with no explicit task_id, which falls back
to HERMES_KANBAN_TASK and resolves the PARENT's card — falsely flipping
it to done with the child's summary while the real deliverable was never
produced (false-done, control-surface-bleed).

Add "kanban" to the composite toolsets stripped from every child in
_strip_blocked_tools, alongside delegation and code_execution. The strip
is unconditional — orchestrator children re-gain delegation by role but
never regain kanban, so no delegated agent holds card-terminal authority
bound to its parent's card.

@cwest cwest left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The root cause holds end to end: a delegated child inherits the parent's HERMES_KANBAN_TASK, and kanban_complete with no explicit task_id falls back to that env var, so a child that kept the kanban toolset would resolve and retire the parent's card. Adding "kanban" to the composite strip set closes that off.

The scoping is right. All four toolset-resolution branches in _build_child_agent route through _strip_blocked_tools (explicit request, parent_enabled inheritance, derived parent set, and the DEFAULT_TOOLSETS fallback), and the orchestrator re-add only restores delegation, never kanban — so no child, leaf or orchestrator, keeps card-terminal authority. The kanban verbs live under exactly one toolset name, and nothing else includes it, so stripping the name is sufficient; there's no alias path that reintroduces them.

The two new tests earn their place: reverting the one-line change turns both red (2 failed, 9 passed), and they assert the contract on both the explicit-request and inherited paths rather than snapshotting a value. Ran the targeted file (11 passed), plus test_delegate.py and test_kanban_tools.py together (252 passed, 0 failed) against the head SHA in a throwaway clone. No changes needed.

@cwest
cwest marked this pull request as ready for review July 19, 2026 19:04
@cwest
cwest merged commit e0e78a0 into cwest/integration Jul 19, 2026
31 checks passed
@cwest
cwest deleted the wt/t_3ee4fbbc branch July 19, 2026 19:07
cwest added a commit that referenced this pull request Jul 26, 2026
A delegate_task child inherits the parent's enabled toolsets AND the
parent's HERMES_KANBAN_TASK env. A child that kept the kanban toolset
could call kanban_complete with no explicit task_id, which falls back
to HERMES_KANBAN_TASK and resolves the PARENT's card — falsely flipping
it to done with the child's summary while the real deliverable was never
produced (false-done, control-surface-bleed).

Add "kanban" to the composite toolsets stripped from every child in
_strip_blocked_tools, alongside delegation and code_execution. The strip
is unconditional — orchestrator children re-gain delegation by role but
never regain kanban, so no delegated agent holds card-terminal authority
bound to its parent's card.

(cherry picked from commit e0e78a0)
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