Repository navigation
fix(kanban): refuse a receipt-less worker completion (no_receipt, rc 4) - #1621
Conversation
A dispatcher-owned worker handoff (expected_run_id set) that closes a running card done with prose only -- no PR ref, survivor claim, attachment, or structured metadata beyond bookkeeping (worker_session_id/pool/no_pr/ no_pr_reason/review_skipped) -- is refused before any mutation with ReceiptRequiredError (reason code no_receipt) and a completion_blocked_no_receipt event. `hermes kanban complete` and `request-review` (milestone_only in-place completion) exit 4 on it. Operator closes, superseded closes and reviewer approvals are not gated. Board knob kanban.receipt_gate (default true). hermes_cli/kanban_receipt.py also lints a board: python -m hermes_cli.kanban_receipt --days 7 [--db PATH] [--json] rc 0 none / 1 found / 2 unreadable. Verified: tests/hermes_cli/test_kanban_receipt_gate.py 10/10; 3 go red with the kernel gate reverted. 20 complete_task/expected_run_id kanban test files + tools/plugins/gateway kanban suites: 1025 passed, 6 failed, all 6 also fail on fork/main 264dcef. Six existing worker-path tests now pass a minimal metadata receipt. Card t_e21aa11c.
…pt (t_e21aa11c) CI on 42c64f6 caught 8 more worker-path tests completing with prose only; each now passes metadata={tests_run: 1}. Verified: the 4 files pass locally.
PRismPrism, formerly FleetReview — same reviewers, new name (until 2026-10-13) Review: pre-merge · head profile: light (rule: default light: lines 413<800, files 15<1000000, hunks 22<1000000, no hot path) · round 0 · members: B-state, C-assert-xhigh, F, G · families: anthropic,openai,xai Confidence: 3/5 Findings
Prism provenance · models: B-state=gpt-6.1-sol, C-assert-xhigh=claude-code-opus-5-5, F=grok-4.7, G=grok-4.7 · cost: $1.85 · duration: 21m 54s · rounds: 1 · files examined: 15 |
|
🤖 merged-by: apollo · lane: kanban-merge-pass · gate: ADVISORY (FleetReview not green for fbed8e7): fleetreview-advisory-20260927-standing.md · why: t_e21aa11c: Kanban: two deploy cards today (t_, t_) closed 'done — no receip; Argus off card review (Ace 13:08), CI green |
…ts, #1584..#1621) 20 conflicted files resolved onto the upstream-extracted modules. Per-commit carry audit (tools/e45-foldcommits.py + symbol greps): every fork/main commit's behavior present in the merged tree; #1595 steer accept/withdraw re-threaded into tools/delegate_tool_registry.steer_subagent and steer_ledger kept out of the RPC snapshot. Test imports repointed tests.run_agent -> tests.agent for the moved incremental-persistence helpers. 0 markers, py_compile clean. Fix-forward of fold reds follows. (t_e45c8c8d)
…ed contracts All six files are fork-only tests that arrived with the fork/main fold and asserted pre-sync shapes; the production behaviour each guards is present: - test_plugins: #819 per-event refusal text (callback/elapsed/budget) and the named 'worker failed to start' skip, instead of the unformatted template. - worker_leftover_reap: facade -> kanban_db_dispatch repoint (e45-kbrepoint); worker completions pass expected_run_id (upstream LiveClaimError fence) and a metadata receipt (#1621 no_receipt gate). - needs_input_pager: link the parent before the dependency wait (upstream 42a778a re-kinds a parent-less dependency block to needs_input). - edit_skills lint contract: allow_real_home_io marker (upstream home I/O guard). - steer_persist: steer is a standalone persisted user row (NousResearch#110979), tool row clean. - followup_timestamp AST: the recursive _run_agent now lives in gateway/run_turn.py. Fold-surface subset: 11 failed -> 0 (targeted reruns). (t_e45c8c8d)
…t + provenance gates - dispatcher-owned completions (fixture pins HERMES_KANBAN_RUN_ID) carry a metadata receipt (#1621 no_receipt gate). - the session-provenance test seeds its session in state.db (upstream 3c33231 rejects phantom session ids). test_kanban_tools: 90 passed / 1 failed. The one left (test_worker_the_dispatcher_never_recorded..., upstream-only) needs a ruling: upstream's self-registered worker (adopt_worker_pid, no spawned event) fails the fork's claim-window identity rule (t_0ae83825), so release_stale_claims reclaims it. (t_e45c8c8d)
…nd_message seal, adapt tests to fork gates / upstream shapes - tools/send_message_tool.py: restore `_is_dispatcher_owned_worker_process` / `_check_send_message` verbatim from fork/main (#636 worker notify-channel seal; fork-only, dropped by the merge). - tests (upstream-only, adapted to fork contracts): test_kanban_provenance — a dispatched worker cannot mint on the placeholder 'default' lane (kanban_worker_policy) and a worker-created card is homed on the owning task (kanban_db._resolve_birth_session C6 #1118), not a tool-supplied session_id; test_kanban_descendant_scope / test_kanban_redaction — completions carry a structured receipt (fork receipt gate #1621, prose alone is refused). - tests (fork-only, adapted to upstream shapes, property kept): test_kanban_authority_ambient_reads — `_require_orchestrator_tool` raises _Reject (handlers return it); sandbox passthrough seal asserts the property (never "task var present + owner marker absent": fork stamped an owner pid, upstream strips the var and fences the lineage); test_kanban_comment_provenance_tools — forged attribution is now refused by the strict-parameter gate instead of silently dropped, and nothing lands; test_kanban_session_attribution — spawn source scan repointed to kanban_db_dispatch (split). Verified via scripts/test-gate: provenance+descendant_scope+redaction 17 passed; authority_ambient_reads+comment_provenance_tools+session_attribution 36 passed.
…ins, launch bound follows claim TTL, cron catch-up opt-out Proved on ace-ai (Linux; these files skip on darwin): - tests/e2e/core/kanban/*: _helpers.Board writes KANBAN_FAST_CONFIG (kanban.rate_limit_cooldown_seconds: 0 — the fork's config beats the FAST_ENV env bridge and load_config fills the 300 s default; receipt_gate: false — #1621 refused the rigs' prose-only kanban_complete). dispatcher restart: body check strips the fork's `origin:` provenance line. rate_limit_review 3 passed; worker_contract 2 passed/2 xfailed; decompose_billing 1 passed/3 xfailed; dispatcher_restart 2 passed. - hermes_cli/kanban_db.py: _dead_claimer_launch_bound_seconds() — the #983 pid-less dead-claimer hold (900 s) follows HERMES_KANBAN_CLAIM_TTL_SECONDS when set; the SIGKILL-mid-tick rig (3 s TTL) otherwise strands claims 15 min. Default unchanged; tests/hermes_cli kanban_db + reclaim_unprovable_liveness + quota_exit: 255 passed. - tests/e2e/core/delivery/test_cron_virtual_clock_soak.py: fixtures pin cron.oneshot_catchup_s: 0 (fork #1087 fires a missed one-shot late; the oracle models the upstream never-fires contract). 5 passed/1 xfailed. - tests/e2e/core/providers/test_openai_codex_pool.py: two cells xfail (strict=False) — they pin upstream's dead-row-on-disk + stdout re-login model that fork #673 (codex_owner receipts) replaced. 1 passed/2 xfailed. Ledger updated: upgrade/git reds are the fork remote lacking release tags newer than v2026.5.7 (N-1 installer predates --non-interactive) -> FOLLOWUP.
A dispatcher-owned worker handoff (expected_run_id set) that closes a running
card done with prose only -- no PR ref, survivor claim, attachment, or
structured metadata beyond bookkeeping (worker_session_id/pool/no_pr/
no_pr_reason/review_skipped) -- is refused before any mutation with
ReceiptRequiredError (reason code no_receipt) and a
completion_blocked_no_receipt event.
hermes kanban completeandrequest-review(milestone_only in-place completion) exit 4 on it.Operator closes, superseded closes and reviewer approvals are not gated.
Board knob kanban.receipt_gate (default true).
hermes_cli/kanban_receipt.py also lints a board:
python -m hermes_cli.kanban_receipt --days 7 [--db PATH] [--json]
rc 0 none / 1 found / 2 unreadable.
Verified: tests/hermes_cli/test_kanban_receipt_gate.py 10/10; 3 go red with
the kernel gate reverted. 20 complete_task/expected_run_id kanban test files
fail on fork/main 264dcef. Six existing worker-path tests now pass a
minimal metadata receipt.
Card t_e21aa11c.
Incident: t_c18e4162 / t_872b6b83 (2026-10-01). Both of those cards DID carry receipts (4 and 5 attachments, plus pcv_before/pcv_after sha tables and live_evidence in run metadata). The session overview printed 'no receipt on card' because it reads only tasks.result, which is empty when a worker hands off via summary. That reader is hermes-home scripts/session-overview.py; it is fixed in a separate hermes-home PR.
Override:
kanban.receipt_gate: falsein the board-home config.yaml (a reason field is not needed: it is a config knob, visible in the config diff and in git history) — operators who must close prose-only; per card, an operatorhermes kanban complete(no dispatcher run id) is not gated, and every refusal leaves acompletion_blocked_no_receiptevent on the card.Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.