fix(kanban): harden orchestration and add report-only workspace lifecycle - #85269
fix(kanban): harden orchestration and add report-only workspace lifecycle#85269ahmadashfq wants to merge 11 commits into
Conversation
…esearch#79738) The unblock-loop breaker routes a repeatedly same-cause-blocked task to 'triage' (block_loop_detected) as a human-in-the-loop gate. The gateway auto-decomposer could not distinguish those cards from fresh triage, so on its next tick it re-specified them (rewriting title/body), promoted them to ready, and left them there under the active_pr respawn guard — non-terminal for external observers (NousResearch#79738, NousResearch#79728). - list_triage_ids(): exclude block-loop-escalated cards (block_loop_detected event with no newer triage_escalation_recovered) - decompose_task(): refuse escalated cards for the auto-decomposer; an explicit manual call is the operator's decision — acknowledge (audited) and proceed (NousResearch#79728) - recover_escalated_triage_task(): operator recovery — clears block_kind, resets block_recurrences (fresh loop budget), appends audited event - hermes kanban unblock --recover-escalated exposes the recovery path Tests: 8 new covering the reporter's exact chain (kind=None review block), typed escalation, operator recovery, fresh-triage regression, and manual decompose of an escalated card. Co-authored-by: Hafiz Ahmad Ashfaq <28647270+ahmadashfq@users.noreply.github.com> Signed-off-by: Hafiz Ahmad Ashfaq <28647270+ahmadashfq@users.noreply.github.com>
…mpose exclusion Covers the block_loop_detected / triage_escalation_recovered events, the fresh-vs-escalated triage distinction, the --recover-escalated operator action, and the manual-decompose acknowledgment path (NousResearch#79738). Co-authored-by: Hafiz Ahmad Ashfaq <28647270+ahmadashfq@users.noreply.github.com> Signed-off-by: Hafiz Ahmad Ashfaq <28647270+ahmadashfq@users.noreply.github.com>
A manual decompose on an escalated card acknowledged the escalation (recover_escalated_triage_task) before the decomposition ran. If the attempt then failed (aux client, LLM error, malformed JSON, empty spec), the card stayed in triage with the escalation cleared: the auto-decompose feed re-included it and the next dispatcher tick re-specified it — the exact automation loop this PR removes. Recovery now happens only after specify_triage_task / decompose_triage_task succeed (both fanout branches), so a failed manual attempt leaves the card escalated and out of the auto-decompose feed, and the triage_escalation_recovered event records an outcome, not an attempt. The recovery predicate no longer requires status='triage' because a successful decompose transitions the card out of triage before the acknowledgment is written; the escalation event predicate remains the gate. Tests: new failure-path regression (failed manual decompose keeps the card escalated, excluded from the feed, still refused by the auto-decomposer, no recovery event) and a fanout=true success-path variant. Co-authored-by: Hafiz Ahmad Ashfaq <28647270+ahmadashfq@users.noreply.github.com> Signed-off-by: Hafiz Ahmad Ashfaq <28647270+ahmadashfq@users.noreply.github.com>
Persist fresh-intake authority, keep legacy triage out of automatic decomposition, and atomically couple escalation recovery with graph/spec writes. Reject duplicate open graphs after the decomposer call and honor the manual promotion gate for single-task specifications. Co-authored-by: Hafiz Ahmad Ashfaq <28647270+ahmadashfq@users.noreply.github.com> Signed-off-by: Hafiz Ahmad Ashfaq <28647270+ahmadashfq@users.noreply.github.com>
Require the decomposer to declare whether each child needs repository writes. Only repo_write children receive isolated worktrees; missing or invalid policy fails closed to scratch, preventing non-code lanes from inheriting a root checkout. Co-authored-by: Hafiz Ahmad Ashfaq <28647270+ahmadashfq@users.noreply.github.com> Signed-off-by: Hafiz Ahmad Ashfaq <28647270+ahmadashfq@users.noreply.github.com>
Add a non-mutating workspace lifecycle authority with SQLite recovery, immutable receipts, exact 54-path baseline comparison, and report-only CLI controls. V1 does not grant removal authority or invoke worktree removal. Co-authored-by: Hafiz Ahmad Ashfaq <28647270+ahmadashfq@users.noreply.github.com> Signed-off-by: Hafiz Ahmad Ashfaq <28647270+ahmadashfq@users.noreply.github.com>
Implement host-owned registry leases, explicit safe reconciliation, immutable receipts, and backup recovery while retaining V1 removal prohibition. Co-authored-by: Hafiz Ahmad Ashfaq <28647270+ahmadashfq@users.noreply.github.com> Signed-off-by: Hafiz Ahmad Ashfaq <28647270+ahmadashfq@users.noreply.github.com>
Remove the incident-specific 54-worktree baseline, bind review packets to exact observed paths and evidence hashes, refuse unmanaged path collisions, and keep V1 apply/removal authority unavailable. Co-authored-by: Hafiz Ahmad Ashfaq <28647270+ahmadashfq@users.noreply.github.com> Signed-off-by: Hafiz Ahmad Ashfaq <28647270+ahmadashfq@users.noreply.github.com>
Make read-only Git inventory deterministic across Windows locale code pages while retaining undecodable bytes as replacement characters for fail-closed classification. Co-authored-by: Hafiz Ahmad Ashfaq <28647270+ahmadashfq@users.noreply.github.com> Signed-off-by: Hafiz Ahmad Ashfaq <28647270+ahmadashfq@users.noreply.github.com>
Co-authored-by: Hafiz Ahmad Ashfaq <28647270+ahmadashfq@users.noreply.github.com> Signed-off-by: Hafiz Ahmad Ashfaq <28647270+ahmadashfq@users.noreply.github.com>
Co-authored-by: Hafiz Ahmad Ashfaq <28647270+ahmadashfq@users.noreply.github.com> Signed-off-by: Hafiz Ahmad Ashfaq <28647270+ahmadashfq@users.noreply.github.com>
|
I reproduced a missing-writer race in the profile lifecycle authority on this HEAD ( Deterministic probe with an isolated DB: hold This falsifies the deletion comment that a concurrent graph commit must either precede the assignment check or observe the identity missing. The actual interleaving can be:
Suggested fix: every mutation that can introduce/change a nonterminal assignee ( |
|
I turned the reproduced The extension preserves legacy never-materialized assignees, serializes assigned task insertion with the lifecycle authority, persists a path-safe retirement fence before rename, and preserves lock order for nested swarm graph creation. Deterministic RED on the author HEAD: the writer completed during the post-check delete pause; GREEN rejects it after waiting, leaves zero stranded cards, and permits a recreated live profile. Focused cluster: 156 passed / 4 skipped; Ruff, changed-production Windows footgun scan, and diff-check pass. It does not merge or copy #86609/#86610. |
fix(kanban): harden orchestration and add report-only workspace lifecycle The fail-closed direction is right: block-loop-escalated triage is excluded from auto-decomposition via durable markers, assignees are revalidated inside the graph commit under a cross-process lifecycle lock, and the workspace registry refuses every removal path. Observations:
|
Summary
This PR closes the Hermes Kanban failure chain where recovery/escalation triage could be mistaken for fresh intake, existing graphs could be duplicated, and non-code children could inherit code worktrees. It also introduces a deliberately report-only workspace lifecycle registry and closeout manifest surface.
Cut 1: safe orchestration boundaries
Report-only Cut 2
Safety boundaries
Verification
Exact commit: 4188f08
Operational rollout
Keep automatic decomposition and child auto-promotion disabled in production until this PR is merged, deployed, and the disposable-board/canary gates pass. This PR does not change live configuration.