## Subsystem invariants

Five contracts apply to every script in `bin/`. Per-file trap doors (below) enforce these at the file level — this section makes the subsystem-wide contract findable before diving into per-file detail.

1. **CLI guard** — Every `bin/` script is a CLI entry-point and MUST have a `if (process.argv[1] && path.basename(process.argv[1]) === '<script>.js')` guard before executing any side-effectful logic. Enforced per-file via `audit-trap-door-enforcement.sh`; canonical `PATTERN_SHAPE` is in the `check-flake-budget.ts` trap door.

2. **StateManager.read()** — Every entry-point script that reads `state.json` MUST go through `StateManager.read()` (not raw `JSON.parse(fs.readFileSync(...))`). The only documented exception is the explicit crash-path `forceWrite` fallback in `mux-runner.ts`. Enforced per-file by the `(state reads)` trap doors in `mux-runner.ts`, `microverse-runner.ts`, `log-watcher.ts`, `morty-watcher.ts`, `raw-morty.ts`, and the `(crash fallback)` trap door in `mux-runner.ts`.

3. **Finite spawn timeout** — Every script that spawns subprocesses MUST pass a finite `timeout` to `spawnSync` / `execFileSync` / `spawn`. Enforced per-file by: `test-runner.ts` trap door, `plumbus-frame-analyzer.ts` trap door (`BUN_TIMEOUT_MS`), R-APMW-6 (`mux-runner.ts`), `spawn-morty.ts` timeout-CLI trap door.

4. **Module Export Catalog** — Every helper module exported from `bin/` that is imported by other modules MUST appear in the `## Module Export Catalog` below. The catalog is the canonical index for import surface; add new exports when you add them to source. Enforced by `audit-subsystem-claude-md.sh` (R-CMD-4 trap door).

5. **Command files can be load-bearing runtime templates** — files under `.claude/commands/` and `extensionRoot/templates/` may be consumed at runtime as the manager-prompt template, not just as user slash-commands: `mux-runner.ts`, `pipeline-runner.ts`, and `jar-runner.ts` resolve `state.command_template` (default `pickle.md`) through `composeManagerPromptFromSkill` (which strips Setup + Step-One). NEVER delete or rename such a file without first grepping `command_template` + `composeManagerPromptFromSkill` for a runtime consumer — deleting `pickle.md` on the "it's just the bare `/pickle` command" premise bricked dispatch (Finding #77 / B-PNTR). Hard enforcement (template-parity + no-bare-`/pickle`) lands with B-PNTR.

## Trap Doors

- `spawn-refinement-team.ts` — INVARIANT: source-AC matches must overwrite analyst `source_prd`/`source_section` with repo-root-relative PRD metadata. BREAKS: readiness flags stale absolute or parent-relative PRD paths and blocks bundle launch. ENFORCE: `extension/tests/refinement-source-prd-relative.test.js`. PATTERN_SHAPE: `source_prd: ticket\\.source_prd \\?\\? sourcePrds\\.join`; INVARIANT: source-AC enrichment must walk reachable `peer_prds` and `composes:` closure before preserving analyst fallbacks. BREAKS: nested PRD provenance drops and readiness re-flags wrong source paths. ENFORCE: `extension/tests/refinement-source-prd-relative.test.js`. PATTERN_SHAPE: `composedPrdPaths\\(|peerPrdDeferredPaths\\(`; INVARIANT: symbol audit must recurse the reachable `composes:` chain before validating declared events/helpers. BREAKS: nested composed symbols go phantom and block refinement. ENFORCE: `extension/tests/spawn-refinement-team-symbol-audit-annotations.test.js`. PATTERN_SHAPE: `resolveComposesChain\\(`.

- `spawn-refinement-team.ts` (R-ACSG matcher + verdict shape) — INVARIANT: `isParametrizedTicket` and `hasJustificationBlock` MUST read the JOINED text of `title`+`acceptance_test`+`justification` (cross-field, via `ticketShapeText(`), NOT a single hard-coded field each; `runAcShapeEnforcement` MUST honor `--skip-ac-shape-gate <reason>` (emitting `ac_shape_gate_bypassed`) and its rejection message MUST name the `ac_id`+ticket id plus a fix template or the override path (`--skip-ac-shape-gate "<reason>"`); the gate is NORMATIVE on analyst ticket shape and ADVISORY on operator PRD prose shape. BREAKS: reverting to `title`-only quantifier / `acceptance_test`-only `describe.each` re-opens the LOA-727 false-reject (~30 min + ~9 worker quotas burned per incident); removing the bypass strands operators when the gate is wrong. ENFORCE: extension/tests/refinement-ac-shape-gate.test.js, bash extension/scripts/audit-trap-door-enforcement.sh. PATTERN_SHAPE: `ticketShapeText(` (or equivalent joined-field helper) consumed by BOTH `isParametrizedTicket` and `hasJustificationBlock`; `--skip-ac-shape-gate` parsed in `parseAndValidateArgs`.
- `spawn-refinement-team.ts` (R-RSU-2/R-RSU-1 bundle-of-bundles over-collapse guard) — INVARIANT: when the input PRD frontmatter declares `composes:` with ≥2 entries AND ≥1 composed source carries a `## Atomic decomposition` section, the analyst prompt MUST carry `BUNDLE_OF_BUNDLES_FANOUT_SECTION` (one ticket per R-code, no umbrella collapse) AND `main()` MUST run `detectBundleOfBundlesOverCollapse` before `writeManifestAtomic`, emitting `refinement_over_collapse_detected` + a `bundle_of_bundles_over_collapse` ticket-quality warning when `manifest.tickets.length <= composedPrdPaths(...).length`; the guard is observability-only (never throws, never changes exit code). BREAKS: removing the prompt section re-opens the section-umbrella over-collapse (incident `2026-05-13-ba01c135` ticket `3ab68cdd`, 67-min wedge); making the guard throw bricks refinement on a false positive. ENFORCE: extension/tests/spawn-refinement-team-bundle-of-bundles.test.js. PATTERN_SHAPE: `BUNDLE_OF_BUNDLES_FANOUT_SECTION` consumed in `buildWorkerPrompt` AND `detectBundleOfBundlesOverCollapse(` called in `main` before `writeManifestAtomic`.

- `mux-runner.ts` (R-ICDM-1 detectManagerMaxTurnsExit turn-budget check) — INVARIANT: `detectManagerMaxTurnsExit(outcome, logFile, maxTurns)` MUST compare actual `num_turns` (falling back to `turn_count`) from the last `result` event against `maxTurns`; it MUST return `false` when either value is `null`/`undefined` (conservative). Callers at lines ~1721 and ~4065 in `mux-runner.ts` and at line ~1412 in `classifyManagerRelaunchExit` MUST pass the real `maxTurns` budget, never `null` as a permanent override. The `.claude/commands/anatomy-park.md`, `.claude/commands/szechuan-sauce.md`, and `.claude/commands/plumbus.md` templates MUST NOT carry `Do NOT output any promise tokens` without a complementary `<promise>TASK_COMPLETED</promise>` instruction. BREAKS: any claude worker that completes cleanly without a legacy promise token gets reclassified as `completion: 'error'` → anatomy-park / szechuan-sauce on claude tears down on iteration 1 (session 2026-05-13-e58dcc1d incident). ENFORCE: extension/tests/integration/mux-runner-claude-iteration-classifier.test.js. PATTERN_SHAPE: `detectManagerMaxTurnsExit\(` callable without a `maxTurns` argument; or any `.claude/commands/*.md` containing `Do NOT output any promise tokens` without a complementary `TASK_COMPLETED` instruction.
- `mux-runner.ts` (R-MMTR-3 claude max-turns relaunch) — INVARIANT: when the manager subprocess on the claude backend exits via `--max-turns` exhaustion (clean Claude CLI `end_turn` exit with non-empty pending-ticket queue), the `mux-runner.ts:3696-3730` relaunch branch MUST call `evaluateManagerRelaunch` (not the legacy `evaluateCodexManagerRelaunch` alias) and respawn up to `Defaults.CLAUDE_MANAGER_RELAUNCH_CAP` (`CLAUDE_MANAGER_RELAUNCH_CAP=20`) times rather than logging `Subprocess error. Exiting loop.`. BREAKS: long pickle phases on claude backend (>=10 tickets per mux iteration) tear down at the 400-turn boundary, stranding remaining tickets; operator must manually `bash launch.sh` to resume. ENFORCE: extension/tests/mux-runner-claude-max-turns-relaunch.test.js, extension/tests/manager-relaunch.test.js.
- `mux-runner.ts` (R-APMW-6 timeout-close ordering) — INVARIANT: timeout resolution must wait for child `close` (or a bounded fallback after `SIGTERM`) before resolving or closing `tmux_iteration_<n>.log`. BREAKS: timeout exits drop shutdown output and can overlap the next manager spawn with a still-dying child. ENFORCE: extension/tests/mux-runner.output-stall.test.js. PATTERN_SHAPE: `proc.kill\\('SIGTERM'\\)` followed by immediate `resolve\\(` or `fs\\.closeSync\\(logFd\\)` outside a `close`-gated path.
- `mux-runner.ts` (R-WSRC-2 schema-ahead graceful exit) — INVARIANT: every non-cap-check `sm.read(statePath)` call site MUST route through `readRunnerState()` which handles `SchemaVersionAheadError`/`SCHEMA_MISMATCH` by calling `recordExitReason('state_schema_version_ahead') + safeDeactivate + process.exit(3)`. BREAKS: a forward-schema state.json (e.g., from a malformed worker write OR mid-deploy schema bump) causes mux-runner to retry-loop at 1 warn/sec indefinitely (R-QGSK-3 wedge incident class). ENFORCE: extension/tests/mux-runner-schema-ahead-graceful-exit.test.js. PATTERN_SHAPE: `grep -c "sm\\.read(statePath)" extension/src/bin/mux-runner.ts` count MUST equal `grep -c "readRunnerState(" + grep -c "classifyCapCheckReadError("`.
- `mux-runner.ts` (orphan-session detection) — INVARIANT: `detectOrphanSessions` must read sibling `state.json` via `readRecoverableJsonObject(...)` before checking `parent_session_hash` / `invocation_source` / `working_dir`. BREAKS: a newer dead-owner `state.json.tmp.*` hides a real orphan manager subprocess and suppresses the iteration-boundary orphan warning. ENFORCE: extension/tests/integration/orphan-session-detection.test.js. PATTERN_SHAPE: `JSON\\.parse\\(fs\\.readFileSync\\(siblingStatePath`.
- `mux-runner.ts` (R-WMW-5 oversized-wedge auto-skip) — INVARIANT: `runMuxRunnerMain` MUST snapshot `countWorkerArtifacts(ticketDir)` BEFORE each `runIteration` call and persist the delta via `recordWorkerArtifactProgress` into `state.worker_artifact_progress[ticketId]` (schema v5, survives R-MMTR manager-relaunch boundary); at `PICKLE_WMW_OBSERVE_K` (default 3) consecutive zero-delta spawns emit exactly one `worker_artifact_progress_zero` event; at `PICKLE_WMW_SKIP_K` (default 5) consecutive zero-delta spawns flip the ticket to `Failed` with `failed_reason: 'oversized_no_progress'` and emit `worker_auto_skip_oversized`. `oversized_no_progress` is operator-recoverable (set `status: Todo` to re-queue). BREAKS: removing the cross-spawn persistence from `state.worker_artifact_progress` resets the zero-progress counter on each R-MMTR manager-relaunch, allowing a genuinely wedged oversized ticket to avoid auto-skip indefinitely and block the pipeline. ENFORCE: extension/tests/integration/worker-manager-wedge-oversized.test.js. PATTERN_SHAPE: `recordWorkerArtifactProgress(statePath, sessionDir, apTicketId, apBeforeCount` called after `runIteration` inside `runMuxRunnerMain`.
- `mux-runner.ts` (R-CMWL-1..4 codex-continuation invariant) — INVARIANT: codex `Session inactive` exit is a relaunchable class gated by `CODEX_MANAGER_RELAUNCH_CAP`; a progressing-incomplete pickle (tickets remain pending after a relaunch) is non-fatal — the outer loop continues; interrupted-ticket work MUST be reset via `resetInterruptedTicketWorkForRelaunch` at the relaunch boundary before the next worker spawn; 2 consecutive zero-progress codex relaunch passes (`codex_manager_consecutive_no_progress >= 2`) MUST halt with `exit_reason: 'codex_manager_no_progress'`. BREAKS: removing the `Session inactive` relaunch branch strands remaining tickets permanently; absent no-progress guard allows infinite codex relaunch loops when no tickets advance. ENFORCE: extension/tests/integration/codex-manager-fixed-wall-continuation.test.js.

- `microverse-runner.ts` (R-SJET-1a stdio invariant) — INVARIANT: judge spawn sites (`measureLlmMetricAttempt` and `probeJudgeCliAvailability`) MUST use `stdio: ['ignore', 'pipe', 'pipe']` in the non-legacy async path. The `PICKLE_JUDGE_LEGACY_SPAWN=1` kill-switch is the ONLY permitted exception and restores `['pipe', 'pipe', 'pipe']` for emergency rollback. No other judge spawn site may use `['pipe', 'pipe', 'pipe']` for stdin. BREAKS: reopens the stdin-hang bug where Claude CLI reads stdin waiting for EOF before producing output (180s × 4 attempts × 2 sessions). ENFORCE: extension/tests/bin/microverse-judge-probe.test.js. PATTERN_SHAPE: `stdio: \['ignore', 'pipe', 'pipe'\]` at judge async spawn sites; `stdio: \['pipe', 'pipe', 'pipe'\]` permitted only inside `PICKLE_JUDGE_LEGACY_SPAWN === '1'` branch.
- `microverse-runner.ts` (R-SJET-3 judge env hygiene) — INVARIANT: both judge spawn sites (`measureLlmMetricAttempt` and `probeJudgeBackendAvailability`) MUST build env via `getJudgeEnvForAttempt(...)`, then layer backend-specific overrides. BREAKS: raw `process.env` leaks `PICKLE_*` or `CLAUDECODE*` session markers into nested judge probes and reopens outer-session contamination/hang regressions. ENFORCE: extension/tests/bin/microverse-judge-probe.test.js. PATTERN_SHAPE: `env: \{ \.\.\.process\.env` at judge spawn/probe call sites.
- `mux-runner.ts`; `pipeline-runner.ts`; `microverse-runner.ts` — INVARIANT: CLI session preflight must accept tmp-only recoverable `state.json` via `readRecoverableJsonObject(...)`, not raw `existsSync(state.json)`. BREAKS: crash-recoverable sessions die at Usage before runner recovery starts. ENFORCE: `extension/tests/runner-entry-recovery.test.js`. PATTERN_SHAPE: `existsSync\(path\.join\(sessionDir, 'state\.json'\)\)` in CLI entry blocks.
- `metrics.ts` (HS-13 backend column completeness) — INVARIANT: per-backend output columns in both daily and weekly tables derive from `BACKENDS` via `buildBackendColumns`, never a hardcoded `claude`/`codex`/`hermes` subset. BREAKS: a backend added to `BACKENDS` (deepseek/grok/kimi/gemini drift) is silently dropped from the breakdown, so columns no longer reconcile to the `Output` total. ENFORCE: extension/tests/metrics.test.js (`metrics.backend-columns` tests). PATTERN_SHAPE: `buildBackendColumns(` used in both `printDailyTable` and `printWeeklyTable`; no literal `'Claude'`/`'Codex'`/`'Hermes'` table headers in `metrics.ts`.

- `status.ts` (pipeline-status recoverable read) — INVARIANT: `readPipelineStatus` reads `pipeline-status.json` via `readRecoverableJsonObject`, never raw `JSON.parse(fs.readFileSync)`, so an interrupted tmp-rename leaves a `.tmp.<pid>` snapshot promoted like the sibling readers in `monitor.ts`/`pipeline-runner.ts`. BREAKS: a crash-orphaned tmp makes the operator recap show stale/empty phases (`X/0`). ENFORCE: extension/tests/status.test.js (`recovers pipeline-status.json from orphan tmp`). PATTERN_SHAPE: `readRecoverableJsonObject(statusPath)` in `readPipelineStatus`; no `JSON.parse(fs.readFileSync(` of `pipeline-status.json` in `status.ts`.

- `microverse-runner.ts` (R-SJET-1b typed-error instanceof-first invariant) — INVARIANT: `classifyJudgeError` MUST check `instanceof JudgeMeasurementTimeout` and `instanceof JudgeMeasurementSpawnFailed` BEFORE any regex fallback. The ETIMEDOUT regex fallback (`/\bETIMEDOUT\b/i`) is the catch-all for raw errors from the async callback path that bypass typed-error wrapping. Callers MUST NOT wrap callback errors in typed classes — raw errors are intentional so the regex fallback preserves existing telemetry assertions (`probe_kind: 'timeout'`, `timeout_class: 'probe_timeout'`). BREAKS: wrapping ETIMEDOUT callback errors in `JudgeMeasurementSpawnFailed` bypasses the regex fallback and reclassifies them as `spawn_failed`, breaking `baseline-attempt-timeout.test.js` and `microverse-baseline-classification.test.js` assertions. ENFORCE: extension/tests/bin/microverse-judge-probe.test.js. PATTERN_SHAPE: `instanceof JudgeMeasurementTimeout` check before `isMissingCliError` and ETIMEDOUT regex in `classifyJudgeError`.
- `microverse-runner.ts` — INVARIANT: dirty-tree preflight rollback must restore the exact pre-existing cached diff after auto-commit failure; only runner-added staging may be undone. BREAKS: hook or identity failures clear operator-staged changes from the index and hide the intended manual commit set. ENFORCE: `extension/tests/microverse.test.js`. PATTERN_SHAPE: `preflightAutoCommit` catch path calling bare `git reset` without restoring a pre-stage cached diff snapshot.
- `microverse-runner.ts` (R-SJWT-1/R-SJWT-TD scoped judge prompt) — INVARIANT: scoped microverse runs (`allowed_paths` non-empty) build the judge prompt over `allowed_paths` via the `allowedPaths.length > 0` branch in `buildJudgePrompt`, never the whole TARGET; the "Target path:" instruction is omitted and replaced with "Review ONLY these paths:" followed by each allowed path enumerated as `- <path>`. BREAKS: re-introducing the whole-tree "Target path:" for scoped runs causes the judge to score out-of-scope violations, producing a non-zero score plateau instead of converging to 0 once all in-scope violations are fixed (HS-12 held at score=8 for 4 iterations pre-fix). ENFORCE: extension/tests/microverse-convergence.test.js (R-SJWT-3 tests). PATTERN_SHAPE: `allowedPaths.length > 0` branch in `buildJudgePrompt` enumerates paths with `'Review ONLY these paths:'` header; `'Target path:'` string absent from scoped-path prompt output.

- `microverse-runner.ts` — INVARIANT: `worker_backend_resolved.source` must be the worker-backend precedence source from backend resolution. BREAKS: schema-backed activity logs reject or misclassify remediator backend telemetry. ENFORCE: `extension/tests/microverse.test.js` remediator activity-event assertion. PATTERN_SHAPE: `event: 'worker_backend_resolved'` with `source` not sourced from `workerBackendResolution.source`; INVARIANT: handoff must advertise `gap_analysis.md` only when the file exists at `gap_analysis_path`. BREAKS: workers are told to read a dead path and lose the real checklist. ENFORCE: `extension/tests/microverse.test.js` gap-analysis handoff coverage. PATTERN_SHAPE: `gap_analysis_path` truthiness check without `fs.existsSync(...)`; INVARIANT: structured judge payloads with numeric `score` must be accepted before backoff/retry logic. BREAKS: full `{score,violations,...}` outputs loop through timeout/failed paths and never advance ledger classification. ENFORCE: `extension/tests/microverse-helpers.test.js` structured-ledger runtime coverage. PATTERN_SHAPE: `extractScore(...)` on judge output without JSON `score` fallback.
- `audit-worker-backends.ts` — INVARIANT: backend audits must apply per-ticket `worker_spawn_backend_override` before inferring expected worker backend from manager-resolution events, but only in real activity order so a stale override cannot outlive a newer `worker_backend_resolved`. BREAKS: intentional codex overrides are reported as cross-backend mismatches, or old overrides hide later claude/hermes mismatches. ENFORCE: `extension/tests/audit-worker-backends.test.js` override-order regression. PATTERN_SHAPE: per-event-type filtering that replays `worker_spawn_backend_override` after later `worker_backend_resolved`; INVARIANT: per-log audits must prefer `worker_spawn_backend_resolved {ticket,pid,backend}` over ticket-level fallback because `worker_session_<pid>.log` is the exact spawn artifact. BREAKS: mixed-backend retries on one ticket are false-flagged or missed when the last ticket-level backend is applied to every historical log. ENFORCE: `extension/tests/audit-worker-backends.test.js` mixed-backend retry regression. PATTERN_SHAPE: `worker_session_<pid>.log` scanned without joining `worker_spawn_backend_resolved.pid`; INVARIANT: Codex-banner detection is a mismatch for every non-Codex expected worker, including Hermes. BREAKS: Hermes sessions silently pass when a Codex worker wrote the log. ENFORCE: `extension/tests/audit-worker-backends.test.js` Hermes mismatch regression. PATTERN_SHAPE: `expectedWorkerBackend === 'claude' && patternsFound.length > 0`.
- `audit-worker-backends.ts` — INVARIANT: session backend audits must read `state.json` through `readRecoverableJsonObject(...)` before replaying `activity` backend events. BREAKS: a newer dead-owner `state.json.tmp.*` can hide codex overrides/resolutions and false-flag or miss worker-log mismatches. ENFORCE: `extension/tests/audit-worker-backends.test.js`. PATTERN_SHAPE: `JSON\\.parse\\(fs\\.readFileSync\\(path\\.join\\(sessionDir, 'state\\.json'\\)`.
- `council-publish.ts` (composeBody markdown-cell escaping) — INVARIANT: every free-text finding cell (`file`, `description`, `rule`, `recommendation`) interpolated into the findings table MUST pass through `escapeTableCell` (`|`→`\|`, CR/LF→`<br>`), AND every free-text trap-door field (`path`, `constraint`, `why_it_breaks`, `what_must_hold`) in the trap-door bullet block MUST pass through `collapseCellNewlines` (CR/LF→`<br>`). BREAKS: a raw `|` or newline in LLM-authored findings splits/misaligns the PR-comment table, misattributing severity/file/rule columns; a raw newline in LLM-authored trap-door text breaks the single bullet and injects arbitrary block-level markdown (headings, lists, `</details>` breakout) into the posted PR comment. ENFORCE: extension/tests/council-publish.test.js (`pipe and newline in finding cells`, `newline in trap-door free text cannot inject block markdown` tests). PATTERN_SHAPE: `escapeTableCell(` wrapping each free-text cell AND `collapseCellNewlines(` wrapping each trap-door field in `composeBody`.
- `test-runner.ts` — INVARIANT: the delegated `node --test` child MUST run under an explicit `spawnSync(..., { timeout })`, with `PICKLE_TEST_RUNNER_TIMEOUT_MS` override clamped to a sane bound. BREAKS: one hung test process wedges `npm run test:*`, gate verification, and release wiring indefinitely. ENFORCE: `extension/tests/bin/test-runner-tier-discovery.test.js`. PATTERN_SHAPE: `spawnSync\\(process\\.execPath, nodeArgs, \\{[^}]*stdio: 'inherit'` without `timeout: getRunnerTimeoutMs\\(\\)`.
- `auto-fill-completion-commit.ts` — INVARIANT: completion-commit inference must read `start_time_epoch` through `readRecoverableJsonObject(statePath)` without any `existsSync(statePath)` pre-gate before filtering git evidence. BREAKS: a newer recoverable `state.json.tmp.*` can hide the real session start and auto-fill a prior-session commit. ENFORCE: `extension/tests/auto-fill-completion-commit.test.js`. PATTERN_SHAPE: `existsSync\\(statePath\\)|JSON\\.parse\\(fs\\.readFileSync\\(statePath, 'utf8'\\)\\)`.
- `cancel.ts` — INVARIANT: `cancelSession` must promote tmp-only recoverable `state.json` via `readRecoverableJsonObject(statePath)` before missing/unreadable checks. BREAKS: `/eat-pickle` rejects live recoverable sessions as missing and leaves the loop active. ENFORCE: `extension/tests/cancel.test.js`. PATTERN_SHAPE: `existsSync\\(statePath\\)` pre-gate before `sm.read\\(statePath\\)` in `cancelSession`.
- `setup.ts` — INVARIANT: resume-time `--worker-backend` must persist to `state.worker_backend` whenever the flag is explicit. BREAKS: `resolveWorkerBackendFromStateFile` keeps routing workers to the stale persisted backend after `/resume`. ENFORCE: `extension/tests/setup.test.js` resume worker-backend override regression. PATTERN_SHAPE: `config.explicitFlags.has('worker-backend')` without a matching `s.worker_backend = config.workerBackend`.
- `setup.ts` (paused-orphan scan) — INVARIANT: `scanPausedOrphans` must read stale session state via `readRecoverableJsonObject(statePath)` before checking `active`/`pid`/`working_dir`, so a newer dead `state.json.tmp.*` snapshot cannot hide a paused orphan from `--paused` demotion. BREAKS: setup skips warning and demotion even though the recoverable snapshot still has `active=true` with no claimant. ENFORCE: `extension/tests/bin/setup-paused-orphan.test.js`. PATTERN_SHAPE: `JSON\\.parse\\(fs\\.readFileSync\\(statePath, 'utf-8'\\)\\)` inside `scanPausedOrphans`.
- `setup.ts`; `src/services/state-manager.ts` (R-PTSB phantom-leak invariant) — INVARIANT: (1) tests invoking session-writing bins (setup.js, mux-runner.js, spawn-morty.js, jar-runner.js) MUST set PICKLE_DATA_ROOT to a tmp directory — enforced by audit-test-isolation.sh's audit_session_bin_sandbox check; (2) setup.ts MUST stamp pid = process.pid into state.json when writing an active session so dead-pid recovery can identify and demote stale entries; (3) state-manager.ts recoverStaleActiveFlag MUST auto-demote active sessions whose pid is null with no live claimant, recording exit_reason = 'orphan-phantom-demoted'. BREAKS: (1) unsandboxed tests pollute the real data root and produce pid-null phantom sessions that block install.sh finalization; (2) missing pid stamp leaves pid-null sessions permanently active with no runtime recovery path; (3) removing the pid-null demotion path in recoverStaleActiveFlag leaves phantoms immune to recovery until the babysitter manual band-aid runs. ENFORCE: extension/scripts/audit-test-isolation.sh, extension/tests/state-manager.test.js.
- `spawn-gate-remediator.ts` — INVARIANT: `worker_spawn_backend_resolved.source` must stay within `BackendResolutionSource` enum semantics (`env` or `default` here). BREAKS: schema-backed remediator telemetry becomes invalid and downstream payload validation drifts. ENFORCE: `extension/tests/bin/spawn-gate-remediator.test.js` activity-event regression. PATTERN_SHAPE: `event: 'worker_spawn_backend_resolved'` with source outside schema enum.
- `log-activity.ts` — INVARIANT: persona CLI emissions must reject events whose schema-required top-level or `gate_payload` fields are absent; `subtool_backend_override` still requires `--backend codex` in `.claude/commands/codex-rescue.md` and `.claude/commands/send-to-morty.md`. BREAKS: shell emitters append schema-invalid activity rows that downstream validators reject. ENFORCE: `extension/tests/log-activity-gate-payload.test.js`, `extension/tests/log-activity-backend-flag.test.js`. PATTERN_SHAPE: `log-activity.js` event payload built without schema-required field validation before `logActivity(...)`.
- `mux-runner.ts` (R-TAQ-3 ticket_audit_failed schema) — INVARIANT: the ticket-audit halt event family MUST stay schema-aligned. Whenever `mux-runner.ts` emits `ticket_audit_failed` (R-TAQ-3 gate halt), the event MUST have a definition in `extension/src/types/activity-events.schema.json` referenced from `oneOf`, an EVENT_CASES row in `extension/tests/activity-event-payload.test.js`, and a row in `spawn-refinement-team.ts:ACTIVITY_EVENT_SCHEMA_SECTION`. BREAKS: a future emitter regression that adds or renames `ticket_audit_failed` payload fields passes silently because no schema/test/prompt covers the event end-to-end (the R-TAQ-3 trap door alone enforces only `ticket_audit_bypassed`). ENFORCE: extension/tests/ticket-audit-failed-schema-conformance.test.js. PATTERN_SHAPE: `event:\s*['"]ticket_audit_failed['"]` in `mux-runner.ts` MUST be matched by a `ticket_audit_failed` definition in `activity-events.schema.json`.
- `mux-runner.ts` (R-WSE-2 worker_partial_lifecycle_exit ts) — INVARIANT: `checkPartialLifecycleExit` emits via `writeActivityEntry`, which validates only the event NAME and does NOT auto-stamp `ts` (unlike `logActivity` in `services/activity-logger.ts`). The producer MUST pass `ts: new Date().toISOString()` explicitly so the JSONL line satisfies schema `required: ['event','ts','ticket','gate_payload']`. BREAKS: removing the explicit `ts` reverts the iter-9 producer/schema disconnect — payload becomes schema-non-conformant, downstream timestamp correlation breaks, and any future Ajv runtime validation on `oneOf` rejects every emission. Same regression class as iter-7 (`ticket_audit_failed`) and iter-8 (`time_cap_disabled_default`). ENFORCE: extension/tests/worker-partial-lifecycle-exit-schema-conformance.test.js, extension/tests/integration/worker-partial-lifecycle-exit.test.js. PATTERN_SHAPE: `event:\s*['"]worker_partial_lifecycle_exit['"]` inside a `writeActivityEntry(...)` call in `checkPartialLifecycleExit` MUST be accompanied by `ts:\s*new Date\(\)\.toISOString\(\)` in the same call.
- `pipeline-runner.ts` — INVARIANT: persisted phase transitions MUST append canonical `{step,timestamp}` entries to `state.history`, not just stamp `state.step`. BREAKS: `verify-recapture-fired.js` cannot derive the anatomy window, so a real `baseline_recapture_attempted` event is misreported as `phase-window-missing`. ENFORCE: extension/tests/pipeline-runner-phase-history.test.js. PATTERN_SHAPE: `event:\s*['"]phase_transition['"]` or `s\.step = phaseConfig\.name` without a same-transaction `s\.history` append.
- `pipeline-runner.ts` (R-PSSS Finding #49 empty-scope skip observability) — INVARIANT: when `resolveAnatomySubsystems` skips because the scope filter excluded every subsystem, it MUST emit `formatEmptyScopeWarn('anatomy-park', ...)` to the log AND a `anatomy_park_empty_scope_skip` activity event; when `setupSzechuanSauce`'s effective scope is non-empty but code-free (`isCodeFreeScope`), `shouldSkipSzechuanForEmptyScope` MUST emit the WARN + `szechuan_sauce_empty_scope_skip` event and skip BEFORE the `init-microverse.js` spawn. An UNSCOPED szechuan run (empty `effectiveAllowedPaths`) MUST still run. Both events carry all 7 registration touchpoints (R-PDD-oneOf). R-PSSS-3: phase setup returns `PhaseSetupResult` (`true` | `{skipReason}`); `runConfiguredPhase` threads `skipReason` and `runPhaseIteration` records it into `counters.phaseSkips` → `pipeline-status.json:phase_skips` (an additive, optional field — omitted when empty). BREAKS: a doc-only / fixture-only branch diff makes anatomy-park / szechuan-sauce a silent no-op the operator can only discover by reading raw logs; collapsing `PhaseSetupResult` back to `boolean` loses the per-phase skip disposition. ENFORCE: extension/tests/anatomy-park-scope.test.js, extension/tests/szechuan-scope.test.js, extension/tests/pipeline-empty-scope-skip-schema-conformance.test.js. PATTERN_SHAPE: `formatEmptyScopeWarn|anatomy_park_empty_scope_skip|szechuan_sauce_empty_scope_skip|PhaseSetupResult`.

## Heal-via-edit-then-resume

Operator workflow to skip or re-classify a ticket mid-session without abandoning the whole epic:

1. Stop the pipeline (Ctrl-C or tmux detach).
2. Edit the ticket's frontmatter: set `status: "Skipped"` (or `"Done"`), add `skipped_reason: "<reason>"` and `completion_commit: "<sha>"`.
3. Run `setup.js --resume <SESSION_ROOT>` — WITHOUT `--force-ticket-status-sync`. The resume honors your edit, emits `setup_resume_ticket_status_preserved`, and continues to the next ticket.

If you want the legacy behavior (auto-correct frontmatter to match `state.current_ticket`), add `--force-ticket-status-sync`. This emits `setup_resume_overrode_ticket_status` and is useful after an unexpected desync where `state.current_ticket` is authoritative.

- `setup.ts` (R-SRTS-1 resume status gating) — INVARIANT: `reconcileTicketStateDesyncOnResume` MUST NOT call `writeTicketStatus(winner, 'In Progress')` unless `forceSync === true`. When `forceSync === false` and the winner ticket's frontmatter disagrees with `state.current_ticket` status, the operator edit is preserved and `setup_resume_ticket_status_preserved` is emitted. BREAKS: reverting the flag gate means `setup --resume` silently overwrites operator-edited ticket frontmatter (R-PPPG ship incident). ENFORCE: `extension/tests/setup-resume-ticket-status-preserved.test.js`. PATTERN_SHAPE: `forceSync` guard before `writeTicketStatus(sessionDir, winner, 'In Progress')` in `reconcileTicketStateDesyncOnResume`.

- `mux-runner.ts` (R-PIWG-1 HEAD pin) — INVARIANT: every iteration in `runMuxRunnerMain` re-checks `state.pinned_branch`/`state.pinned_sha` via `checkHeadPinMismatch` before ticket selection; an external branch switch sets `exit_reason='working_tree_modified_externally'`, emits `head_mismatch_detected`, and calls `safeDeactivate`. Pipeline-internal commits on a named branch do NOT trigger this (branch name unchanged). BREAKS: removing the pre-ticket check allows a parallel `git checkout` to silently shift the branch under a live pipeline. ENFORCE: extension/tests/integration/head-pin-mismatch-detection.test.js. PATTERN_SHAPE: `checkHeadPinMismatch\(` before ticket selection in `runMuxRunnerMain`.

## Resume-time ticket runnability contract

Precedence: ticket frontmatter `status:` is authoritative for runnable/skipped decisions. The runner reads it fresh per iteration via `getTicketStatus(sessionDir, ticketId)` (`extension/src/services/pickle-utils.ts`) inside `isPendingMuxTicket` (`extension/src/bin/mux-runner.ts:471-480`). All other sources are advisory:
1. ticket frontmatter `status:` — AUTHORITATIVE; values `Todo` / `In Progress` are runnable, `Done` / `Skipped` are not (`isPendingMuxTicket` short-circuits via `normalizeTicketStatus`)
2. `state.current_ticket` — single-active-ticket lock for the in-flight iteration; cleared between tickets, does NOT gate runnability of other tickets
3. `pipeline.json.completed_phases` — phase-advance ledger, not a per-ticket gate
4. `refinement_manifest.json[].status` — informational metadata only; NOT consulted at runtime for runnability (the runner reads ticket frontmatter, not the manifest)

There is no `state.failed_tickets` / `state.blocked_tickets` / `state.skipped_tickets` field in this codebase — a parallel runnability set would be a regression. R-RMBS-3 emits `ticket_runnability_resolved` per iteration to surface the runner's decision for observability without changing the underlying mechanism.

Heal flow recipe: To make a previously-failed or skipped ticket runnable again:
1. Stop the pipeline (Ctrl-C or `eat-pickle`).
2. Edit the ticket's frontmatter file at `<SESSION_ROOT>/<hash>/linear_ticket_<hash>.md`: set `status: Todo`.
3. (Optional Finding #36 workaround if `state.current_ticket` points at this same ticket): set `state.current_ticket = null` BEFORE running setup.js — only needed when running an older deployed setup.js that lacks R-SRTS-1.
4. Re-run `setup.js --resume <SESSION_ROOT>`. The runner will pick up the ticket via `findNextPendingTicketId` (frontmatter read). Do NOT edit `refinement_manifest.json` for this purpose — the runner does not consult it for runnability.

- `mux-runner.ts` (R-RMBS-1/R-RMBS-3 frontmatter authority) — INVARIANT: `isPendingMuxTicket` is the canonical pendingness check; it MUST read ticket frontmatter via `getTicketStatus(sessionDir, ticketId)` and return `false` only for `done`/`skipped` statuses. NO field in `state.json` may parallel this decision — `state.failed_tickets`, `state.blocked_tickets`, `state.skipped_tickets` are FORBIDDEN field names that would re-introduce the heal-flow papercut (Master Plan Finding #41). Per-iteration `ticket_runnability_resolved` event emits `{ ticket_id, frontmatter_status, runnable, reason }` for observability. BREAKS: reintroducing a parallel set in State means an operator who edits ticket frontmatter back from Skipped to Todo cannot make the ticket runnable again without also clearing the parallel set, defeating the heal flow recipe. ENFORCE: extension/tests/runnability-contract-doc-shape.test.js, extension/tests/integration/runnability-frontmatter-authoritative.test.js. PATTERN_SHAPE: `state\.(failed|blocked|skipped)_tickets` MUST NOT appear in `extension/src/bin/mux-runner.ts` or `extension/src/types/index.ts`.

- `mux-runner.ts` (R-RIC-EXPLICIT-4 phantom-revert reachability) — INVARIANT: the phantom-Done batch loop (`batchLoopPhantomDoneKind`) MUST decide keep-vs-revert via `gateForPhantomDoneRevert(ctx, { flags })` (the `ticket-completion-evidence.ts` oracle, R-AFCC-DEEP-4A migration), NOT a bespoke `source !== 'absent'` check; the oracle maps `persist-inferred` → `'inferred'`, `keep` → `'explicit-reachable'`, and `revert` → `'absent'`, and (per R-AFCC-STAGE) maps `inferred-stale` to keep because a stored-but-unverifiable SHA is still evidence. BREAKS: collapsing the gate back to a lenient `source !== 'absent'` check (the pre-oracle phantom-revert path) lets a ticket with a stamped-but-unreachable `completion_commit` (typo, foreign repo, dropped commit) keep status Done forever, defeating phantom detection (R-CCR-1 regression caught at v1.80.3 release gate; masked from the worker by the test:fast 240s timeout). ENFORCE: extension/scripts/audit-phantom-done-call-sites.sh, extension/tests/mux-runner.test.js (R-CCR-1 block). PATTERN_SHAPE: `gateForPhantomDoneRevert(` in `batchLoopPhantomDoneKind` returning `'inferred'` / `'explicit-reachable'` / `'absent'`.
- `check-readiness.ts` (R-RTPS-1 tilde-path skip) — INVARIANT: `extractContractReferences` MUST skip backticked tokens that begin with `~/`, `$HOME/`, or `${HOME}/` before either PATH_RE or symbol-shape extraction runs; these are runtime deploy paths (verified by R-CLOSER-3 via `bash install.sh` parity check) and have no source-tree counterpart. BREAKS: ticket text citing runtime deploy paths produces spurious `file_path` findings (live incident 2026-05-10 session `2026-05-10-84ad0873`, 7 false positives across tickets `010f5c8b` and `4dcf9b43`). ENFORCE: extension/tests/check-readiness-tilde-paths.test.js. PATTERN_SHAPE: `~/|\$HOME/|\$\{HOME\}/` skip predicate inside `extractContractReferences` backtick loop.

## R-CCPM-1 codex manager payload scrub

INVARIANT: every codex-manager-subprocess detection path that fires `codex_manager_self_bootstrap_attempted` MUST stamp `ts: new Date().toISOString()` explicitly before calling `writeActivityEntry` (or `logActivity`), because `writeActivityEntry` does NOT auto-stamp `ts`. The `action_taken` field MUST be the literal string `'logged'` (not `'blocked'` or `'aborted'`) — it records what the guard DID, not what it prevented. The `ticket` field is nullable: pass `state.current_ticket ?? null`, never omit the key. The `attempted_argv` field MUST be the actual `process.argv` slice passed to the subprocess, trimmed of the node binary but preserving all flags — never a reconstructed or abbreviated form.

PATTERN_SHAPE: `event: 'codex_manager_self_bootstrap_attempted'` in any emitter MUST be accompanied by `ts: new Date().toISOString()`, `action_taken: 'logged'`, and `ticket: state.current_ticket ?? null`.

BREAKS: omitting `ts` makes the payload schema-non-conformant (same class as R-WSE-2 `worker_partial_lifecycle_exit` iter-9 disconnect). Using `action_taken: 'blocked'` fails the `const: 'logged'` schema constraint. Omitting `ticket` violates the `required` array and fails `activity-event-payload.test.js` drop-field tests.

ENFORCE: `extension/tests/codex-manager-self-bootstrap-attempted-schema-conformance.test.js`, `extension/tests/activity-event-payload.test.js`.

## Probe vs Measurement Timeout Distinction (R-MJCP-8)

`probeJudgeCliAvailability` is a fail-fast existence check (≥5s default via `PICKLE_JUDGE_PROBE_TIMEOUT_MS`, max 60s). Only `kind: 'missing'` (ENOENT-class) short-circuits to `judge_cli_missing`. `kind: 'timeout'` or `kind: 'failed'` fall through to the measurement loop so a slow cold-start does not kill the convergence run.

`measureLlmMetricAttempt` is the correctness-check with 4-attempt retry-with-backoff (10s/30s/60s between attempts). ENOENT here also produces `failureKind: 'cli_missing'`; ETIMEDOUT produces `failureKind: 'timeout'`. The shared `classifyJudgeError` helper is used in both paths — no duplicate ENOENT/ETIMEDOUT branches.

## Manager-turn freshness contract (R-SJLAG)

The session state file's mtime advances at least once per artifact-write during a manager turn. When `mux-runner.ts` detects that artifact files (`research_*.md`, `plan_*.md`, `conformance_*.md`) under the current ticket dir gained a newer mtime, it calls `fs.utimesSync` on the state file (mtime bump only — no content write) and emits a `manager_turn_progress` activity event.

Operator signal: a state file that is >N min stale with NO recent `manager_turn_progress` activity event indicates a genuine wedge, not a slow-but-working turn.

## Module Export Catalog

Machine-maintained export index for the `bin/` subsystem. The audit script treats these names as the minimum subsystem surface that this document covers.

- `archaeology.ts` -> `ArchaeologyArgs`, `ArchaeologyRunOptions`, `ArchaeologyRunResult`, `buildArchaeologyPrompt`, `normalizeProjectContext`, `parseArgs`, `runArchaeology`
- `audit-ticket-bundle.ts` -> `auditSession`, `checkMissingAuditComment`, `checkPathDrift`, `detectCrossDocNamingDrift`, `extractForwardCreatePaths`
- `audit-worker-backends.ts` -> `scanSession`
- `auto-fill-completion-commit.ts` -> `AutoFillCompletionCommitInput`, `AutoFillCompletionCommitResult`, `autoFillCompletionCommit`
- `calibrate.ts` -> `main`, `parseArgs`, `runCalibrate`
- `cancel.ts` -> `cancelSession`, `cleanupStaleIndexLock`
- `check-flake-budget.ts` -> `checkFlakeBudgetMain`
- `check-gate.ts` -> `CheckGateMainOpts`, `checkGateMain`
- `check-readiness.ts` -> `ForwardRefAnnotation`, `ReadinessArgs`, `ReadinessFinding`, `extractAcceptanceCriteria`, `extractContractReferences`, `extractForwardRefAnnotations`, `findReadinessFindings`, `isMachineCheckable`, `loadReadinessAllowlist`, `parseArgs`, `runHistory`, `runReadiness`
- `check-scope-diff.ts` -> `CheckScopeDiffOpts`, `ScopeDiffResult`, `checkScopeDiff`
- `check-update.ts` -> `BlockedDowngradeError`, `CheckForUpdateOptions`, `PerformUpgradeOptions`, `checkForUpdate`, `compareSemver`, `downloadRelease`, `extractAndInstall`, `getCurrentVersion`, `getLatestRelease`, `isCacheStale`, `parseVersion`, `performUpgrade`, `readCache`, `readSettings`, `writeCache`
- `correct-course.ts` -> `CorrectCourseArgs`, `CorrectCourseRunOptions`, `CorrectCourseRunResult`, `CourseCorrectionProposalValidationInput`, `CourseCorrectionProposalValidationResult`, `buildCorrectCourseBrief`, `main`, `parseArgs`, `runCorrectCourse`, `validateCourseCorrectionProposal`, `validateDiscovery`
- `council-publish.ts` -> `CouncilPublishError`, `PrListParse`, `PublishOptions`, `PublishReport`, `PublishResult`, `composeBody`, `parsePrList`
- `debate.ts` -> `DebateArgs`, `DebateRunOptions`, `DebateRunResult`, `DebateSettings`, `buildDebateBrief`, `main`, `parseArgs`, `runDebate`
- `finalize-gate.ts` -> `FinalizeGateOpts`, `FinalizeGateSettings`, `finalizeGateMain`, `loadFinalizeGateSettings`, `resolveFinalizeSettingsRoot`
- `generate-debate-personas.ts` -> `DEBATE_PERSONAS`, `DebatePersonaDefinition`, `DebatePersonaName`, `debateAgentFilename`, `generatedDebatePersonas`, `renderDebatePersona`, `writeDebatePersonas`
- `get-session.ts` -> `getSessionPath`
- `jar-runner.ts` -> `IntegrityResult`, `RunTaskResult`, `SpawnResult`, `TaskMeta`, `buildJarNotification`, `discoverMarinatingTasks`, `handleTaskEnoent`, `loadJarTaskTimeout`, `skipTaskWithReason`, `validateTaskIntegrity`
- `log-watcher.ts` -> `formatToolUse`, `processLine`
- `metrics.ts` -> `parseMetricsArgs`
- `microverse-runner.ts` -> `ExitOutcome`, `IterationClassification`, `JudgeMeasurementSpawnFailed`, `JudgeMeasurementTimeout`, `MetricSnapshot`, `NoCommitExitClassification`, `PerIterationGateDeps`, `RunContext`, `StallClassifierInput`, `_deps`, `appendGapAnalysisFixedBlock`, `applyTestBackendOverrideFromEnv`, `buildEfficiencySection`, `buildFailureDistribution`, `buildJudgePrompt`, `buildMicroverseHandoff`, `classifyJudgeError`, `classifyNoCommitExit`, `classifyStall`, `currentExitForFailureHistory`, `deactivateRunnerState`, `ensurePerIterationGateBaseline`, `ensureRunnerStateActive`, `executeGapAnalysis`, `executeMainLoop`, `extractScore`, `getBestScore`, `handleIterationOutcome`, `handleNoCommitStall`, `handleRateLimit`, `handleWorkerManagedIteration`, `injectRecoveryGuidance`, `loadConvergenceGateSettings`, `loadFailureClassificationFlag`, `loadPassModelOverrides`, `main`, `mapBaselineMeasureExitReason`, `markMicroverseFatalError`, `maybeEmitConsecutiveNoProgressWarning`, `measureAndClassifyIteration`, `measureLlmMetric`, `measureLlmMetricWithBackoff`, `measureMetric`, `parseLlmJudgeOutput`, `preflightAutoCommit`, `probeJudgeBackendAvailability`, `readRunnerState`, `resetGapAnalysisForAmnesiacBreaker`, `resolvePassModelOverride`, `runPerIterationGateHook`, `runRemediatorForIteration`, `stageAutoCommitPaths`, `writeFinalReport`
- `monitor.ts` -> `MONITOR_STDERR_CAP_BYTES`, `MONITOR_STDERR_LOG_NAME`, `MONITOR_STDOUT_WATCHDOG_MS`, `MonitorMode`, `MonitorWriteSink`, `RESPAWN_WATCHDOG_INTERVAL_MS`, `appendMonitorStderrLog`, `buildMonitorStderrHeader`, `buildTicketLines`, `checkAndSwapMode`, `createMonitorStderrCapture`, `formatCurrentField`, `inferModeFromStep`, `isRespawnWatchdogDisabled`, `readPipelineLifecycle`, `renderDashboard`, `renderElapsedField`, `renderMicroverseDashboard`, `renderMicroverseTrend`, `shouldMonitorExit`, `sparkline`, `startRespawnWatchdog`, `summarizeLine`, `writeWithWatchdog`
- `morty-watcher.ts` -> `classifyArtifact`, `discoverArtifacts`
- `mux-runner.ts` -> `ApplyAutoTicketCompletionInput`, `AutoTicketCompletionValidation`, `BetweenTicketGateFailure`, `BetweenTicketGateResult`, `COMMIT_PENDING_HANDOFF_TEXT`, `CapCheckReadDecision`, `CircuitBreakerBudget`, `CommitGatePassingDeliverableInput`, `CommitGatePassingDeliverableReason`, `CommitGatePassingDeliverableResult`, `CommitPendingProbeInput`, `CommitPendingProbeResult`, `CorrectPhantomDoneTicketsInput`, `EpicCompletionDecision`, `EvaluateEpicCompletionInput`, `ExitReason`, `LoopAction`, `LoopContext`, `MuxReadinessGateInput`, `OrphanDetectionResult`, `OrphanedFastTestRunner`, `PhantomDoneInspectResult`, `PhantomDoneKind`, `SparkSmokeGateAction`, `SparkSmokeGateDecision`, `SparkSmokeGateRule`, `TicketAuditGateInput`, `TicketAuditGateResult`, `TicketDesyncResolution`, `TimeoutCounterInput`, `TimeoutCounterState`, `TimeoutHaltContext`, `appendPipelineRunnerMarker`, `applyAllTicketsDoneCompletion`, `applyAutoTicketCompletionValidation`, `applyTicketTierBudget`, `applyTimeoutCounter`, `buildTmuxNotification`, `buildWorkerGateFailureSummary`, `checkFailedAfterResearchApproved`, `checkHeadPinMismatch`, `checkIterationLogForCodexSelfBootstrap`, `checkPartialLifecycleExit`, `classifyCapCheckReadError`, `classifyCompletion`, `classifyGitProbeError`, `classifyIterationExit`, `classifyManagerRelaunchExit`, `classifyTicketCompletion`, `clearStalePerTicketCacheAtIterationStart`, `clearStaleDoneWithoutCommitEvidence`, `clearStaleTicketCacheFields`, `commitGatePassingDeliverableOnExitPath`, `commitPendingProbe`, `computeRateLimitAction`, `correctPhantomDoneTickets`, `detectManagerMaxTurnsExit`, `detectMultiRepo`, `detectOrphanSessions`, `detectOutputFormat`, `detectPkgJsonVersionDrift`, `detectRateLimitInLog`, `detectRateLimitInText`, `evaluateCloserTerminalState`, `evaluateCodexManagerRelaunch`, `evaluateEpicCompletion`, `evaluateManagerRelaunch`, `evaluateMuxIdleStallWatchdog`, `evaluateSparkSmokeGate`, `executeTimeoutHalt`, `extractAssistantContent`, `findPendingNonCurrentTickets`, `getCircuitBreakerBudget`, `guardCompletionCommitBeforeDone`, `hasCompletionCommit`, `hasStalePerTicketCacheFields`, `hasSubstantiveManagerHandoff`, `inspectPhantomDoneTicketFile`, `isSchemaVersionAheadError`, `isValidPerTicketCapCache`, `killCurrentChild`, `loadMeeseeksModel`, `loadRateLimitSettings`, `observeCodexToolCallStream`, `parseBetweenTicketFastGateFailures`, `parseOrphanedFastTestRunnersFromPs`, `processCompletionBranch`, `processIterationOutcome`, `processRateLimitCycle`, `readRunnerState`, `reapOrphanedFastTestRunnersOnStartup`, `recordCodexManagerRelaunch`, `recordManagerRelaunch`, `repairZeroWorkerTimeout`, `resolveIdleStallThresholdSeconds`, `resolveTicketDesyncWinner`, `runBetweenTicketFastGate`, `runBetweenTicketFastTests`, `runIteration`, `runMuxReadinessGate`, `runTicketAuditGate`, `setupSignalHandlers`, `shouldExitMainLoop`, `stalePerTicketCacheDiagnostic`, `stripSetupSection`, `transitionToMeeseeks`, `truncateTaskNotes`, `validateAutoTicketCompletion`, `validateStartupState`, `writeHandoffAtomic`, `maybeEmitManagerTurnProgress`, `detectAndRecoverHeadRegression`, `FAILED_FLIP_SUPPRESSED_STRATEGY`, `FailedFlipCallsite`, `FailedFlipEvidenceKind`, `FailedFlipSuppressionDecision`, `FailedFlipSuppressionInput`, `evaluateFailedFlipSuppression`, `readActiveFailedFlipHolds`
- `pipeline-runner.ts` -> `BackendSource`, `BundlePreflightError`, `ChildMuxRunnerHeartbeatHandle`, `CloserReleaseActions`, `CloserReleasePlan`, `MainOpts`, `MicroverseHaltDecision`, `PhaseConfig`, `PhaseName`, `PhaseSetupResult`, `PhaseSkipReason`, `SetupArgs`, `SetupScopeArgs`, `SpawnRunnerFn`, `SpawnRunnerResult`, `__setCitadelRemediationDepsForTests`, `__setCloserReleaseActionsForTests`, `__setSpawnRunnerForTests`, `applyEpochResetOnReconstruction`, `applyStrictPhasesOverride`, `armChildMuxRunnerHeartbeat`, `assertCleanWorkingTree`, `assertCodexRequiredBackend`, `buildCloserReleasePlan`, `claimPipelineRunnerActive`, `classifyMicroverseHaltDecision`, `cleanPhaseArtifacts`, `discoverSubsystems`, `enterPicklePhase`, `executeCitadelPhase`, `executeCloserReleasePlan`, `executePhaseRunner`, `installShutdownHandlers`, `isFatalPhaseFailure`, `isTestFile`, `logPhaseContinueReason`, `logPhaseHaltReason`, `main`, `parsePipelineConfig`, `postPhaseCleanup`, `readBundlePrdBackend`, `readCitadelReport`, `recordRecoverablePhaseFailure`, `resetInterruptedTicketWorkForRelaunch`, `resetStateForPhase`, `resolveBackendWithSource`, `runBundlePreflight`, `samplePhaseHistoryTimestamp`, `setupAnatomyPark`, `setupPhase`, `setupScope`, `setupSzechuanSauce`, `shouldHaltAfterPhase`, `writePipelineStatus`, `writeSkippedByScope`, `writeWatcherLivenessArtifact`
- `prune-activity.ts` -> `pruneActivity`
- `raw-morty.ts` -> `processLineRaw`
- `retry-ticket.ts` -> `retryTicket`
- `setup.ts` -> `CodegraphIndexAtSetupDeps`, `DEFAULT_MANAGER_IDLE_BACKOFF_FALLBACK_MS`, `McpSnapshotFetchFn`, `SetupArgs`, `codexVersionSatisfiesRange`, `countManifestTickets`, `displaySetupSummary`, `evaluateLaunchSizing`, `handleResumeSession`, `initializeNewSession`, `parseArguments`, `precleanPausedOrphansBeforeCreate`, `resolveCodexVersionForSetup`, `resolveManagerIdleBackoffFallbackMs`, `resolvePipelineContinueOnPhaseFailSetting`, `runCodegraphIndexAtSetup`, `runMcpSnapshot`, `scanPausedOrphans`
- `spawn-gate-remediator.ts` -> `SpawnGateRemediatorOpts`, `spawnGateRemediatorMain`
- `spawn-morty.ts` -> `ALL_LIFECYCLE_PHASES`, `BuildWorkerPromptOptions`, `ParsedArgs`, `TicketSpec`, `WorkerProcessContext`, `buildTierLifecycleSections`, `buildTierResumeTable`, `buildWorkerPrompt`, `checkGitEdits`, `computeChangedLoc`, `isPhasePersonasEnabled`, `parseAndValidateArgs`, `parseBackendOverrideArg`, `resolveCodexModel`, `resolveEffectiveTimeout`, `resolvePhasePersonaModel`, `resolveWorkerGateTier`, `resolveWorkerModelFromTierAndPersona`, `runWorkerGate`, `runWorkerProcess`, `tierToModel`
- `spawn-refinement-team.ts` -> `ACTIVITY_EVENT_SCHEMA_SECTION`, `AcShapeSmell`, `AcShapeViolation`, `AnchorCitation`, `CycleResults`, `PATH_VERIFICATION_PROMPT_SECTION`, `PathVerificationWarning`, `PortalContext`, `RefinementArgs`, `RefinementManifest`, `RefinementSettings`, `RefinementTicketManifestEntry`, `StaleAnchorWarning`, `SymbolAuditCategory`, `SymbolAuditFinding`, `SymbolAuditReference`, `SymbolAuditReport`, `TicketQualityWarning`, `__resetRefinementBackendWarning`, `buildRefinementEnv`, `buildRefinementManifest`, `buildRefinementWorkerInvocation`, `buildWorkerPrompt`, `checkAnalystOutputPaths`, `emitStaleAnchorWarnings`, `enrichManifestTicketsFromSourcePrds`, `evaluateAcShapeAdvisory`, `evaluateAcShapeEnforcement`, `evaluateSymbolAudit`, `extractAnchorCitations`, `findStaleAnchorWarnings`, `isParametrizedTicket`, `loadRefinementSettings`, `orchestrateCycles`, `parseAcShapeSection`, `parseAndValidateArgs`, `parseForwardCreateAnnotation`, `renderSymbolAuditMarkdown`, `resolveComposesChain`, `runAcShapeEnforcement`, `runReadinessGate`, `runSymbolAuditEnforcement`, `scanAnalystOutputsForUnverifiedPaths`, `warnIfCodexRequested`, `writeManifestAtomic`, `writeSymbolAudit`
- `standup.ts` -> `GitCommitEntry`, `GitOnlyCommit`, `classifyStandupNoise`, `deduplicateCommits`, `formatOutput`, `getCurrentUserEmail`, `getGitCommits`, `parseArgs`, `readActivityFiles`
- `status.ts` -> `computeConsecutiveNoProgress`, `showStatus`
- `update-state.ts` -> `updateState`
- `validate-teams-ticket.ts` -> `ParsedArgs`, `main`, `parseArgs`
