Fix reviewer BLOCK: the stateless poll loop re-planned every terminal card each
tick, so SHIP and the two cycle-limit escalations - whose source cards stay in
the done state - re-fired their comment/block on every pass (~2880/day/chain).
- Add a persistent emission Ledger (/opt/data/supervisor/emitted.json): SHIP and
escalate perform their action only when the (action, target) key is absent,
then record it, so each fires at most once and survives a pod restart. Spawns
remain self-limiting via the existing dedup scan.
- Cycle-limit escalations now target the SOURCE review/repair card (not the impl
root), so the card also leaves the done state and is skipped next tick even if
block_task round-trips imperfectly.
- Harden the _spawn TypeError fallback: re-run the dedup scan before retrying so
a post-insert TypeError can never double-insert.
- Add across-ticks idempotency tests (10x supervise_once -> exactly one
comment/flag/block) plus ledger persistence/corruption and spawn-guard tests.
Both modules stay 100% line+branch, <500 LOC. Stacks on the merge train
(base 5f27e50c).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Drive the cross-card implement->review->repair->re-review chain from inside
the pod so unattended runs no longer stall once the first implementation card
completes. Today that chain exists only as an external codex-shepherd session;
this adds a bounded in-pod poll loop that reads board state via
hermes_cli.kanban_db and creates Kanban follow-up cards (subscription lanes
only) with no provider/metered path of its own.
- kanban_supervisor.py (I/O shell) + supervisor_policy.py (pure state machine):
impl-done+PR -> review; review SHIP -> mark impl ready-for-human (never
merges/approves/clears WIP); review BLOCK -> bounded repair; repair new
commit -> re-review. Fail-closed on unparseable/ambiguous state; per-
(parent, head_commit) dedup safe beside the external shepherd; bounded review
<->repair cycle count and max concurrent chains.
- Deployed as a hardened non-root sidecar (drop ALL caps, read-only rootfs, no
runtime-access/credential mount) alongside model-steward; scripts packaged in
the coordinator configMapGenerator.
- Gated by new kanban.auto_supervise config key (default false, re-read each
tick like auto_decompose) so it is inert until the external shepherd retires.
- Fix latent goal_max_turns NULL fallback in cli_lane_execution (1 -> documented
default 20).
- 62 new behavioral tests at 100% line+branch on both modules.
Stacks on the merge train (base 5f27e50c).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>