Ticket graphs

Every ticket as the root of its provenance graph — goal, patch, approval, runs and (as the ticket-class build lands) mandate, manifestations, guarantees, journey, artifacts and children. Rendered through the <<<TicketGraphList>>> tag.

← all ticket-graphs

DONE#439 congruency

Redo #279 pair_loop no-verdict-crash fix + lazy re-ask registration — WITHOUT the assign-before-ACTIVE regression; selftest must cover the live governance path

goal

Re-do ticket #279's pair_loop.py work, which was HARVESTED then REVERTED on 2026-07-15 because it shipped a dispatch-killing regression its selftest did not catch. WHAT #279 WAS FOR (still wanted): * Fix the harness no-verdict crash: a worker that returns nothing readable (or done=false) must FAIL THE ROUND gracefully — not crash the pair. The worktree persists with whatever was written and a fresh worker runs the next round. * Lazy per-spawn registration so a RE-ASKED agent can exist at all: its id and birth prompt are not known until its predecessor is rejected, so agent.register + ticket.assign must happen at spawn time, immediately before each agent runs. THE REGRESSION IT INTRODUCED (must NOT recur): * By moving registration to lazy-at-spawn, #279 left `pair()` calling `rest("process_status", {"id": tid, "status": "ACTIVE"})` BEFORE any agent was assigned. The governance DB enforces an integrity constraint: "a ticket authorizes an agent: assign one (ticket.assign) before it can go ACTIVE" (SQLSTATE 23000). So EVERY new dispatch 500'd at "pair (round 1)" — the pipeline's core function was dead. Only already-ACTIVE pairs survived. HARD REQUIREMENTS FOR THE REDO: 1. process_status -> ACTIVE MUST run AFTER at least one ticket.assign on the ticket (e.g. assign the worker, or the scribe, first; only then flip ACTIVE — ACTIVE need only be set once, on round 1). 2. Keep the no-verdict-crash fix and the lazy re-ask registration. 3. The --selftest MUST exercise the LIVE governance ordering (a real process_status->ACTIVE after an assign, against the actual constraint), not only the throwaway in-memory DB. #279 passed 129/129 precisely because its selftest never hit the assign-before-ACTIVE rule. A regression that takes down all dispatch must be catchable by the selftest. DELIVERABLE: checkouts/current/congruency/tools/pair_loop.py (behavior-preserving except the two fixes above). ACCEPTANCE: `pair_loop.py --selftest` passes AND a real `--ticket N` dispatch on a REQUESTED forge unit reaches ACTIVE and spawns its worker (no 500), verified live.

patch

none

approval

unapproved

runs

no runs recorded

mandate (clauses)

not yet recorded — lands with the ticket-class build

manifestations

not yet recorded — lands with the ticket-class build

guarantees

not yet recorded — lands with the ticket-class build

journey (blunders & successes)

not yet recorded — lands with the ticket-class build

artifacts (forge)

not yet recorded — lands with the ticket-class build

source (forge tree)

browse congruency source (forge-parked tree)

children

not yet recorded — lands with the ticket-class build