Skip to content

fix(kanban): auto-decompose children lose project_id/workspace_path/branch_name - #105669

Open
iankoratskydcn wants to merge 1 commit into
NousResearch:mainfrom
iankoratskydcn:fix/kanban-decompose-project-linking
Open

iankoratskydcn wants to merge 1 commit into
NousResearch:mainfrom
iankoratskydcn:fix/kanban-decompose-project-linking

Conversation

@iankoratskydcn

Copy link
Copy Markdown

Bug

kanban.auto_decompose (via decompose_triage_task → _insert_decomposed_child → _resolve_project_link) produces child cards with project_id, workspace_path, and branch_name all null whenever the project can't be resolved through the normal registry lookup path — e.g. when the source task's project isn't in the decomposing profile's local projects.db (worker profiles have independent projects.db files; the Kanban DB is shared).

Reproduced live: a triage card whose project bound correctly (project_id, absolute workspace_path, real branch_name) was decomposed into 6 children, all of which showed workspace_kind: worktree but every resolving field null — human-readable show printed Workspace: worktree @ (unresolved). This is the same failure class as an earlier manually-decomposed card that needed a manual "malformed child execution envelope: project_id and branch_name missing" repair before a builder could run.

Fix

_resolve_project_link in hermes_cli/kanban_db.py:

  • When the direct project-registry lookup misses and no explicit project_source_task_id is given, fall back to the earliest sibling task on the same project_id that has a resolved workspace_kind='worktree' + non-null workspace_path, and recover the project from it.
  • If that recovery also fails (registry + branch-derived slug recovery both miss), retain the project link from a canonical absolute worktree task's parent directory (<repo>/.worktrees/<id> convention) instead of silently dropping the link and degrading to an unlinked scratch child.

Also included in this commit (same original changeset, kept together per the author's own note that these were verified as one green unit):

  • Decompose double-fire guard (idempotent decomposed event check).
  • promote_task gains a readiness=True escape hatch for triage-status inspection canaries, requiring a non-empty audit reason.

Conflict note

This was originally committed against an older main. Current main already refactored kanban_db_graph.py's decompose_triage_task/_insert_decomposed_child into thin delegators to the canonical implementation in kanban_db.py (see that file's own docstring, which independently describes this exact bug class: "this module used to own a full, independently-maintained duplicate that silently dropped project_id/branch_name/skills from every decomposed child"). Rebased the cherry-pick onto that delegation; the actual _resolve_project_link fix applied cleanly since it lives in kanban_db.py, not the removed duplicate.

Testing

scripts/run_tests.sh tests/hermes_cli/test_kanban_cli_dispatch_passthrough.py tests/hermes_cli/test_kanban_decompose_db.py tests/hermes_cli/test_kanban_promote.py tests/hermes_cli/test_kanban_worktree_isolation.py
# 13/13 passed

scripts/run_tests.sh tests/hermes_cli/ -k "kanban and not notify"
# 317/317 passed, 0 failed, 2 skipped (platform-only)

test_kanban_notify.py failures (13 tests) are a pre-existing, unrelated pytest.mark.asyncio registration issue reproduced identically on unmodified main — not caused by this change.

test_kanban_decompose_db.py::test_decompose_preserves_project_execution_metadata and ::test_project_link_recovers_from_canonical_task_when_registry_is_unavailable are the direct regression tests for this bug class.

…adiness

Pre-existing uncommitted work found in this checkout (from a separate,
concurrent Hermes session sharing this same ~/.hermes/hermes-agent
working copy) at a green, tested state. Committed as-is, separately
from the per-board dispatch toggle commit, per explicit instruction
to keep the two changesets isolated rather than conflate them.

Covers (inferred from diff, not authored this session):
- kanban_db.py: _resolve_project_link / set_project_id and related
  project-binding helpers; specify_triage_task additions.
- kanban_db_graph.py: consolidated/simplified decompose graph logic
  (net -177 lines vs kanban_db.py's +258 — looks like a graph-logic
  relocation alongside the double-fire guard fix, not just growth).
- kanban_db_workspace.py, kanban_ops.py: small supporting changes.
- promote_task readiness parameter (kanban_db.py / test_kanban_promote.py).
- Test coverage: test_kanban_cli_dispatch_passthrough.py,
  test_kanban_decompose_db.py (new file), test_kanban_promote.py,
  test_kanban_worktree_isolation.py.

Verified before commit: all 9 files syntax-clean at staged content;
scripts/run_tests.sh on the 4 affected test files: 13/13 passed.
@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/cron Cron scheduler and job management labels Sep 8, 2026
@alt-glitch

Copy link
Copy Markdown

This was generated by AI during triage.

Related: #75601, #91205, #103714 and #42660 are open competing fixes for the same auto-decompose child-anchoring class (children persisted with null project_id / workspace_path). This PR recovers the link via sibling tasks and the .worktrees/<id> path convention; #103714 instead asks each child for its own repo and refuses unanchored children. Flagging the cluster so a maintainer can pick one mechanism. Note this PR also bundles a decompose double-fire guard and a promote_task readiness escape hatch that are unrelated to the title fix.

@zachlendon

Copy link
Copy Markdown

We hit this in production on v0.21.5 (f97608f). With auto_decompose: true, children of a worktree root are inserted with no project_id, branch_name or inherited workspace_path. On a board whose default workdir isn't a git repo, every such child fails at spawn: "workspace_kind=worktree but board default_workdir … is not inside a git repo". We saw at least 6 children stranded this way in one day. A single board fallback doesn't help for mixed-repository roots, so parent-project inheritance as in this PR is the fix we need. A regression test that reads the child's project and worktree provenance after decomposition would be great.

This branch has not been deployed

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

Labels

comp/cron Cron scheduler and job management P3 Low — cosmetic, nice to have type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants