Skip to content

fix(kanban): linking a ready card under an unfinished parent records why it dropped to todo (#110996, salvage #111005) - #111468

Merged
teknium1 merged 3 commits into
mainfrom
fix/kanban-link-demotion-visible
Sep 15, 2026
Merged

teknium1 merged 3 commits into
mainfrom
fix/kanban-link-demotion-visible

Conversation

@teknium1

@teknium1 teknium1 commented Sep 15, 2026 •

Copy link
Copy Markdown
Collaborator

Linking a ready card under a parent that is not done no longer demotes it to todo silently: the board records a dependency_wait event, and hermes kanban link, the kanban_link tool and the dashboard API's POST /links all report the gate (the dashboard UI itself does not yet surface it).

Fixes #110996

  • hermes_cli/kanban_db.py::link_tasks returns True when it demoted the child and appends dependency_wait {reason: parent_not_done, demoted: true, parent} (mirrors the claim_review_task demotion event; gated on rowcount == 1 so a todo child gets no spurious event).
  • hermes_cli/kanban.py::_cmd_link prints a one-line note naming the parent and the unlink escape hatch; tools/kanban_tools.py::kanban_link returns gated / gated_by; plugins/kanban/dashboard/plugin_api.py::add_link returns gated.
  • Docs: dependency_wait event row documents the new payload; a caution block in the delegate_task vs Kanban section states the rule the reporter's fleet adopted (never link a support card under the card it exists to unblock; reference it in the body).
  • Two invariant tests in tests/hermes_cli/test_kanban_db.py (event on demotion; none for a done parent), both red on origin/main.
  • Scope: the reporter's option 1 (a claim-honoured --force) is not taken. promote_task on origin/main already refuses undone parents with an error pointing at unlink (02005cf, kanban promote --force prints "Promoted <id> -> ready" and does not change the status (false success) #106195), and the thread (reporter included) endorsed the visibility half over re-opening that door. fix(kanban): allow forced support children of blocked parents #110999 by @KoNit-K implements option 1 and is a design reversal for the maintainer to rule on, not a salvage.

Live repro: env -u HERMES_DELEGATED_CHILD_CONTEXT python /tmp/batch111/kanban/probe_kanban_db.py <tree> <label> — temp HERMES_HOME, blocked parent, ready child, link_tasks(parent, child).

origin/main (2179a27) this branch (93abc9a)
link ready child under blocked parent child ready->todo events=['created', 'linked'] → SILENT DEMOTION child ready->todo events=['created', 'dependency_wait', 'linked']
control: link under a done parent status=ready events=['created', 'linked'] unchanged
promote_task on the gated child refuses: unsatisfied parent dependencies … drop the link with hermes kanban unlink unchanged (already fixed on main)

Root cause: link_tasks ran the ready → todo demotion as a bare UPDATE and appended only linked, so the only trace of the deadlock was the later claim_rejected events.

Credit

Salvages #111005 by @kokhlo (cherry-picked as-is; follow-up commit adds the dashboard surface, the docs rule, and drops the CLI prose test). Option 1 alternative #110999 by @KoNit-K noted above.

Infographic

kanban-link-demotion-visible

Review fixes

  • Fixed — create_task(parents=[open parent]) / kanban_create (the reporter's actual incident path) parked the card in todo with no dependency_wait event and no gated in the tool payload. Now emits the same dependency_wait {reason: parent_not_done, parent} event and kanban_create returns gated / gated_by, mirroring kanban_link. Test: test_create_task_with_open_parent_emits_dependency_wait + gated assertion in test_create_happy_path.
  • Fixed — link_tasks gated on status != 'done' while _parents_satisfied/recompute_ready treat archived as terminal, so linking a ready child under an archived parent demoted it with a false reason and the next recompute promoted it back. Gate is now not in ('done', 'archived'). Test: test_link_tasks_archived_parent_is_terminal_no_gate.
  • Left — dashboard dist/index.js addLink/addChild discard the response, so only the API reports the gate; PR body wording adjusted above rather than editing the built bundle.

@github-actions

github-actions Bot commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

૮ >ﻌ< ა ci review

ran on 1f3a0e0 — fix(kanban): gate create-with-parents like link; archived pa

⚠️ Warnings

OSV vulnerability scan · View job

76 known vulnerabilities found in pinned dependencies.

How to fix:

Review the findings in the Security tab. Update the affected dependencies if a patched version is available.


CI timings · View report · View job

Wall time 13m31s vs 6m9s (+119.8%). 11 job(s) slower, 2 faster, 2 unchanged.

  • Python tests / Run tests: -70.0s
  • Docs Site / docs-site-checks: +54.0s
  • OS-specific tests / Windows-only tests: +23.0s
  • Python lints / Windows footguns (blocking): +17.0s
  • Profile artifact check / Reject profile archives: +13.0s

@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/cron Cron scheduler and job management comp/plugins Plugin system and bundled plugins comp/tools Tool registry, model_tools, toolsets sweeper:risk-automation Sweeper risk: may affect CI, automerge, label sync, or maintainer automation labels Sep 15, 2026
@kyssta-exe

Copy link
Copy Markdown
Contributor

Review: fix(kanban) ready-card demotion records its reason

Summary: Linking a ready child under a non-done parent silently demoted it to todo; now link_tasks returns a gated bool, appends a dependency_wait {reason: parent_not_done, demoted: true, parent} event (only when rowcount == 1), and all three surfaces (CLI, kanban_link tool, dashboard POST /links) report it. Docs updated. All required checks pass.

What changed:

  • hermes_cli/kanban_db.py::link_tasks: -> bool, gated from cur.rowcount == 1, new event before linked
  • hermes_cli/kanban.py::_cmd_link, tools/kanban_tools.py::_handle_link (gated/gated_by), plugins/kanban/dashboard/plugin_api.py::add_link (gated)
  • tests/hermes_cli/test_kanban_db.py: demotion-event test + done-parent control; website/docs/user-guide/features/kanban.md caution block, tool-table and event-table rows

Strengths: Event gating on rowcount == 1 avoids spurious events for already-todo children; mirrors the existing claim_review_task demotion-event pattern; scope discipline explicit (option-1 --force deferred for maintainer ruling); repro table shows silent-vs-visible behavior plus unchanged control.

Findings: Return-type change from None to bool is technically breaking for external callers; fine in-repo (all three call sites updated), but grep for other link_tasks( callers (plugins/scripts) before merge. Non-blocking: (1) the CLI note prints even in scripted use — consider stderr or TTY-gating so Linked … on stdout stays parseable; (2) docs nit: the caution's "Reference the parent id in the support card's body instead" would benefit from a one-line example.

Verdict: Looks good to merge.

Reviewed using Hermes-Agent

kokhlo and others added 3 commits September 15, 2026 05:54
A ready child linked under an unfinished parent drops to todo with no
event and no operator signal; the only trace used to be claim_rejected
after a forced promote. Record a dependency_wait event when the demotion
fires, return the gate from link_tasks, warn in the CLI link command,
report gated in the kanban_link tool, and document the gate.
…iant tests

The dashboard's POST /links is the fourth writer of link_tasks (CLI, tool,
dashboard, plus the graph builder); return the same ``gated`` flag so every
surface that can create the deadlock can see it. Document the
``dependency_wait`` payload the link path emits and the delegation rule the
reporter derived (never link a support card under the card it unblocks).

Drops the CLI output test (a change-detector on prose); the two DB-level
invariants (event emitted on demotion / none for a done parent) stay.
…erminal

create_task(parents=[open parent]) — the reporter's actual incident path —
parked the card in todo with only a `created` event, and kanban_create's
payload carried no `gated`, so the board still showed an unexplained todo
while only the link surface was fixed. create_task now appends the same
dependency_wait {reason: parent_not_done, parent} event and kanban_create
returns gated/gated_by, mirroring kanban_link.

link_tasks gated on `status != 'done'`, but _parents_satisfied and
recompute_ready treat `archived` as terminal: linking a ready child under an
archived parent demoted it to todo with a false parent_not_done event and the
next recompute promoted it straight back. Gate on not in ('done','archived').

Review finding: create_task(parents=...) emitted no dependency_wait/gated; link under an archived parent flapped ready->todo->ready with a false reason.
@teknium1
teknium1 force-pushed the fix/kanban-link-demotion-visible branch from 1f3a0e0 to b3a07fb Compare September 15, 2026 12:58
@teknium1
teknium1 merged commit 6f24245 into main Sep 15, 2026
37 checks passed
@teknium1
teknium1 deleted the fix/kanban-link-demotion-visible branch September 15, 2026 13:25
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 comp/plugins Plugin system and bundled plugins comp/tools Tool registry, model_tools, toolsets P3 Low — cosmetic, nice to have sweeper:risk-automation Sweeper risk: may affect CI, automerge, label sync, or maintainer automation type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cards created as children of a blocked parent are unclaimable by construction: claim_task re-rejects parents_not_done even after promote --force

4 participants