100%

Section 06 — Autonomous-Execution Engine

Cites §01 north star (invariants 1, 6, 7, 8, 14, 16, 18); grounded in Pass 1D + Pass 2 (consolidation map + 7 risks). One group, flat capability nodes (refinement 6 — avoids the second-system monolith while honoring “one engine designed once”).

Intelligence Reconnaissance

Run 2026-05-28:

  • scripts/intel-query.sh dag-ascii scripts-first-restructure — §06 linear-walk position: §05 → §06 → §07. Per INV-19 (Strict-Linear-Single-Branch DAG — every node has exactly ONE predecessor; references/restructure-charter-seed.md §2 INV-19), §06’s depends_on is narrowed to the SOLE DIRECT predecessor ["05"]; §03 + §03A are TRANSITIVE predecessors (they precede §05 in the linear chain — §03/§03A → §04 → §05 → §06 per [ori:plans/scripts-first-restructure/00-overview.md:110]) and are reachable through §05, never listed as direct edges (a multi-entry depends_on would declare a non-single-predecessor shape INV-19 rejects). §03/§03A/§05 are all status: complete (§05 also reviewed: true) per their frontmatter SSOTs, so the transitive chain is satisfied. §03A is the substrate-verification close-out gate §06.4 leans on (it verified the §03.1 completion.gates_verified schema); that dependency is honored transitively through §05 (a §05-complete state implies §03A-complete by the linear chain), NOT via a direct 03A edge.
  • scripts/intel-query.sh plan-status scripts-first-restructure — §03/§03A/§05 status: complete; §06 in-review; §07-§12 not-started (§06 feeds §12 soak, never gates on it) per [ori:plans/scripts-first-restructure/index.md].
  • rules.HaltReason enum (direct file citation — wrapper Python is not reliably indexed in the intel graph, so this bullet anchors on the source file, not a file-symbols query) is the SSOT §06.1 halt_reasons.py re-exports + partitions (no duplicate enum) at scripts/plan_orchestrator/rules.py (the HaltReason enum definition).
  • CANONICAL_EXIT_REASONS + EXIT_REASON_ROUTING closed-enum SSOT (direct file citation) §06.3 route_walk anchors exit_reason→next_action parity on at scripts/plan_corpus/exit_reasons.py; the gate_internal_error routing row reconciled by §06.1 lives at scripts/plan_corpus/exit_reasons.py:604.
  • target-self + redispatch cure shapes §06.2 consolidates (direct file citation): scripts/plan_orchestrator/autopilot_auto_cure.py defines the cure shapes; the _compose_resume_bash argv splitters to collapse live there + in the linear_execution / review_blocked dispatch siblings under scripts/plan_orchestrator/.
  • STRUCTURE:invariant-acceptance-hook-missing detector §06.4 CONSUMES (never re-authors) (direct file citation) at scripts/plan_corpus/cross_section_check.py.
  • scripts/intel-query.sh bugs-for plans/scripts-first-restructure — no open blockers; 12 BUG-07-NNN absorbed-via-§06 entries closed obe pointing here per [ori:bug-tracker/closed-bugs.json].

Results summary: §06 sits at the §05 → §06 → §07 boundary with all three predecessors (§03, §03A, §05) at status: complete per their frontmatter SSOTs (§05 also reviewed: true); rules.HaltReason + CANONICAL_EXIT_REASONS are the two closed-enum SSOTs the engine re-exports and partitions (never duplicates); the §03/§03A substrate parser SSOT (migrations/006_md_to_json.py:build_plan_json_from_dir) is the parse surface route_walk REUSES (never re-implements); the cure argv-splitter duplication spans autopilot_auto_cure + linear_execution + review_blocked dispatch (all collapse into §06.2’s single compose_resume_bash); cross_section_check.py already exists and is consumed (not authored) by §06.4 and §12.1.

Node-grouping — five capability nodes in one section (size-cap reconciliation)

plan-audit.py SIZE_VIOLATION flags §06 at 40 top-level items (cap 20). This packing is DELIBERATE and is NOT promoted to sibling sections, per the following reconciliation:

  • The mission demands ONE autonomous-execution engine GROUP “designed once” (refinement 6 + Mission Success Criteria §06 row). Promoting 06.1/06.2/06.3 to sibling sections would fracture the single-group framing into the second-system multi-section sprawl the refinement explicitly guards against.
  • The five capability nodes FAIL the routing.md §4 independence test: they do NOT have independent deliverables completable cold. cure_dispatch.py (06.2) imports the halt_reasons.py (06.1) partition; route_walk.py (06.3) is the SOLE caller of both gates + serve_next + cure_dispatch; review-as-phase (06.4) is invoked by route_walk as the completion choke point; path-scoped-commit + soak (06.5) consume route_walk’s exit states. They share ONE locked module boundary (scripts/plan_orchestrator/ engine surface) and ONE composite deliverable (the zero-halt autonomous engine). A session cannot pick up 06.2 without 06.1’s enum landed first.
  • The flat-node model groups these as ONE group: architectural engine node-cluster (per routing.md §1 flat-node group-label projection); the group label NEVER determines section boundaries — the engine is one cohesive unit whose subsections are sequencing steps, not independently-workable siblings.
  • Size discipline is honored by the per-capability acceptance-test table (§06.N) which caps each node’s verification surface; the body density is the cohesion the “one engine” mission requires, not unmanaged sprawl.

Goal

See frontmatter goal.

  • §26/27/28/31/32/34/36 = cross-plan refs to the SUBJECT plan’s on-disk section-26-*.mdsection-36-*.md, NOT same-plan subsections of this restructure plan.
  • Zero-halt: cure_dispatch resolves every curable halt inline; only genuine + user-decision halts survive.
  • Status SSOT: this section’s frontmatter status: in-review is canonical. The orchestrator API view (audit_api_view.md) may resolve a stale api_status: in-progress from a prior routing-layer projection; the .md frontmatter wins per state-discipline.md §1, and the routing layer re-syncs from frontmatter on the next plan-corpus pass. The in-review state is the legitimate §03/§05-satisfied re-entry recorded in 00-overview HISTORY (2026-05-28), not in-progress execution work.

06.1 — halt_reasons.py

  • Author scripts/plan_orchestrator/halt_reasons.py (ABSENT today per Pass 1D/Pass 2). Re-export rules.HaltReason (no duplication). Categorize: CURABLE = {PLAN_SCOPE_DEADLOCK, SCHEMA_INVALID, AUTOPILOT_BLOCKED, TARGET_SELF_DRIFT, PIVOT_CHAIN_TARGET_SELF, REVIEW_PLAN_REDISPATCH_LOOP, LINEAR_EXECUTION_BLOCKED, REVIEW_BLOCKED_NO_BUG_POINTER} (each a distinct rules.HaltReason member — no conflation; LINEAR_EXECUTION_BLOCKED and REVIEW_BLOCKED_NO_BUG_POINTER are CURABLE because both have LIVE auto-cure dispatchers in scripts/plan_orchestrator/ today — linear_execution_cure_dispatch and review_blocked_cure_dispatch respectively, consolidated into §06.2’s single registry — so a member with a live auto-cure dispatcher MUST land in CURABLE, never GENUINE); GENUINE = the remaining halt-only members (derived as set(rules.HaltReason) - CURABLE - USER_DECISION - {RESIDUAL_AUTO_ACKNOWLEDGED}, NOT a hard-coded count); USER_DECISION = {drift_cure_required_user_decision}.
  • Enum-vs-string partition authority (cc-user-decision-enum-vs-string — drift_cure_required_user_decision is a string-keyed halt at scripts/plan_orchestrator/auto_cure_loop.py:73, NOT a rules.HaltReason enum member, yet it sits in this same 06.1 categorization block as the enum-derived sets): the CURABLE/GENUINE/USER_DECISION/QUARANTINE partition declared in this subsection applies to rules.HaltReason ENUM MEMBERS ONLY. String-keyed halts that never become enum members (drift_cure_required_user_decision, the commit_push halt strings, the non-enum orchestrator halt strings gate_internal_error / drift_cure_residual_auto_acknowledged) are partitioned by the SEPARATE HALT_STRING_SOURCES producer-SSOT mechanism (next checkbox below) — test_halt_reason_partition_exhaustive iterates ONLY rules.HaltReason (enum) and test_halt_string_partition_exhaustive iterates ONLY the HALT_STRING_SOURCES strings; the two tests are disjoint and jointly exhaustive. drift_cure_required_user_decision is therefore authoritatively categorized by HALT_STRING_SOURCES (USER_DECISION disposition) — it is referenced in the USER_DECISION set above for readability but its partition membership is OWNED by the string mechanism, never the enum iteration. Acceptance: test_user_decision_string_partition_owner (in tests/test_halt_reasons.py) asserts drift_cure_required_user_decision is enumerated by HALT_STRING_SOURCES (not by set(rules.HaltReason)) and lands in USER_DECISION via the string mechanism, so the two partition surfaces never both claim it.
  • Each GENUINE member declares an autopilot_disposition ∈ {log_and_continue, quarantine, structured_exit} (per skill-control-contract.md §Autopilot Mode); the registry rejects a GENUINE member with no disposition. Acceptance: test_halt_reason_partition_exhaustive (in scripts/plan_orchestrator/tests/test_halt_reasons.py) iterates rules.HaltReason and asserts every member is in exactly one of CURABLE/GENUINE/USER_DECISION/QUARANTINE or is the documented RESIDUAL_AUTO_ACKNOWLEDGED continuation, and that every GENUINE member has a disposition — so a new HaltReason member breaks the test until categorized.
  • Non-enum halt-string partition coverage (codex+opencode CONVERGENT — enum-iteration alone leaves the string-keyed halts untested): the categorization in halt_reasons.py MUST cover BOTH the rules.HaltReason enum members AND the string-keyed halts that never become enum members — the commit_push halt strings (test_all_fail, extended_check_fail, messages_invalid, diff_digest_mismatch, push_rejected_non_ff, push_network_failure, authorized_writes_violation, banned_commit_msg, dirty_after_commit, auth_required per scripts/commit_push/rules.py / .claude/rules/commit-push-rules.json) and the non-enum orchestrator halt strings (drift_cure_required_user_decision, gate_internal_error, drift_cure_residual_auto_acknowledged). halt_reasons.py exposes a HALT_STRING_SOURCES producer-SSOT tuple naming each string source so the test enumerates from the source, never a hard-coded list. Each named producer MUST expose a concrete programmatic enumeration API the test iterates (no string literals copied into the test): (1) the commit-push halt SSOT .claude/rules/commit-push-rules.json (loaded via scripts/commit_push/rules.py) exposes COMMIT_PUSH_HALT_STRINGS: frozenset[str] derived from the JSON halt_reasons keys, NOT a re-typed literal set; (2) scripts/plan_orchestrator/auto_cure_loop.py exposes AUTO_CURE_LOOP_HALT_STRINGS: frozenset[str] covering drift_cure_required_user_decision (today an inline string at auto_cure_loop.py:73); (3) scripts/plan_corpus/invariant_gate.py exposes INVARIANT_GATE_HALT_STRINGS: frozenset[str] covering gate_internal_error; drift_cure_residual_auto_acknowledged is derived from LoopExitReason.RESIDUAL_AUTO_ACKNOWLEDGED.value (scripts/plan_orchestrator/auto_cure_loop.py), never a copied literal. HALT_STRING_SOURCES = (COMMIT_PUSH_HALT_STRINGS, AUTO_CURE_LOOP_HALT_STRINGS, INVARIANT_GATE_HALT_STRINGS, ...) is the union the test walks. Partition coverage extends to EVERY halt-class exit reason in scripts/plan_corpus/exit_reasons.py CANONICAL_EXIT_REASONS whose EXIT_REASON_ROUTING row is a halt-class disposition, so an un-categorized external-skill halt string cannot bypass the partition test. Acceptance: test_halt_string_partition_exhaustive (in scripts/plan_orchestrator/tests/test_halt_reasons.py) enumerates EVERY string from each HALT_STRING_SOURCES producer API + EVERY halt-class CANONICAL_EXIT_REASONS member and asserts each lands in exactly ONE halt_reasons.py disposition set (CURABLE / GENUINE / USER_DECISION / QUARANTINE) or the documented RESIDUAL_AUTO_ACKNOWLEDGED continuation — a newly-added commit_push halt string, orchestrator halt string, or halt-class exit reason fails the test until categorized; the paired NEGATIVE test_halt_string_sources_are_programmatic asserts each producer API is sourced (a frozenset derived from its producer module), never a hard-coded literal copied into halt_reasons.py, closing the gap where test_halt_reason_partition_exhaustive (enum-only) silently skips string-keyed halts.
  • Document RESIDUAL_AUTO_ACKNOWLEDGED as a CONTINUATION signal, NOT a halt (Pass 2 risk 7.7) — exclude from CURABLE/GENUINE.
  • gate_internal_error carve-out (reconciles GENUINE with zero-halt INV-7): gate_internal_error (per scripts/plan_corpus/invariant_gate.pyCLINormalizationError → exit 3 / halt_reason: gate_internal_error) is a GENUINE halt and IS the documented zero-halt carve-out. Zero-halt (INV-7) bans halts for ROUTABLE conditions (a blocked node, a curable drift, a completion-claim discrepancy) — every such condition becomes a cure or a quarantine. gate_internal_error is NOT a routable plan-state condition: it signals the gate harness itself malfunctioned (a normalization crash, a corrupt invariant spec), so the engine has no trustworthy route to compute. It carries autopilot_disposition: structured_exit — the engine emits exit state for the caller orchestrator (never an interactive prompt, never action: halt mid-walk for a plan-state reason), and the malfunction is recorded to active-plan HISTORY. Acceptance: test_gate_internal_error_is_genuine_carveout asserts gate_internal_error ∈ GENUINE, carries autopilot_disposition: structured_exit, and is the ONLY GENUINE member whose trigger is harness-malfunction rather than plan-state; the test documents that this is the single zero-halt carve-out so INV-7 stays “zero halts for routable plan-state conditions” exactly.
  • gate_internal_error producer-vs-engine routing reconciliation (ar-gate-internal-error-conflict — scripts/plan_corpus/exit_reasons.py:604 routes gate_internal_error with caller_action: halt_and_report, a CONCRETE contradiction with this section’s autopilot_disposition: structured_exit): update scripts/plan_corpus/exit_reasons.py so the gate_internal_error EXIT_REASON_ROUTING row carries caller_action: structured_exit (the disposition the engine requires for autopilot zero-halt), replacing halt_and_report — the routing table is the SSOT and MUST agree with halt_reasons.py, never diverge. halt_and_report was the interactive-mode shape; structured_exit subsumes it (the caller orchestrator decides whether to report-to-user in interactive mode or log-and-route in autopilot, per skill-control-contract.md §Autopilot Mode). The engine does NOT override the routing table at runtime — both surfaces are reconciled to structured_exit at the source so there is ONE authority. Acceptance: test_gate_internal_error_routing_reconciled (in scripts/plan_corpus/tests/test_exit_reasons.py) asserts EXIT_REASON_ROUTING["gate_internal_error"]["caller_action"] == "structured_exit" AND a cross-check test_gate_internal_error_disposition_matches_routing (in tests/test_halt_reasons.py) asserts halt_reasons.py’s gate_internal_error autopilot_disposition equals the exit_reasons.py caller_action — so a future edit to either surface that re-diverges them fails the test.
  • INV-17 (per decisions/01-completion-integrity-invariants.md): add a NEVER-CURABLE member completion_claim_unverified to rules.HaltReason at scripts/plan_orchestrator/rules.py (mirroring the completion_verification_exhausted / soak_nonconvergence enum additions below — test_halt_reason_partition_exhaustive iterates rules.HaltReason and asserts QUARANTINE coverage, so the class MUST be an enum member) — a node deriving done whose deliverable-existence verification fails. Make it a FOURTH partition set QUARANTINE (alongside CURABLE / GENUINE / USER_DECISION) so the exhaustive partition is closed over it: it is NOT in CURABLE (never auto_script/llm_bounded-acknowledged) and NOT a GENUINE halt; QUARANTINE members route to the §06.4 relocate-back-to-not-done path (NOT action: halt), reconciling zero-halt with verification. test_halt_reason_partition_exhaustive (line above) asserts every member lands in exactly one of CURABLE/GENUINE/USER_DECISION/QUARANTINE (or RESIDUAL_AUTO_ACKNOWLEDGED continuation) — completion_claim_unverified is the QUARANTINE member, so it can no longer sit outside the declared partition. cure_dispatch MUST NOT have ANY handler that resolves a QUARANTINE member by refreshing a hash, acknowledging the claim, or any auto_script/llm_bounded path. Acceptance: test_completion_claim_unverified_is_quarantine_never_cured (in tests/test_halt_reasons.py) asserts completion_claim_unverified ∈ QUARANTINE, is in NO other set, and that cure_dispatch.dispatch("completion_claim_unverified", ctx) returns a relocate/quarantine CureResult with NO hash-refresh or claim-acknowledgment action (paired with §06.2 test_cure_dispatch_no_completion_claim_handler).
  • Fold the commit_push halt strings (test_all_fail, extended_check_fail, …) into the categorization.
  • Add the GENUINE member completion_verification_exhausted to rules.HaltReason (the §06.4 quarantine-retry-cap escalation target) with autopilot_disposition: log_and_continue; it is the only halt that the §06.4 choke point may escalate to, and it is in GENUINE (never CURABLE — a node that fails verification N times is not auto-cured). Because route_walk emits it as an exit_reason, it is ALSO registered in scripts/plan_corpus/exit_reasons.py CANONICAL_EXIT_REASONS + an EXIT_REASON_ROUTING row (mirroring the no_cross_plan_ready_node registration) so the §06.3 test_route_walk_exit_reason_parity subset check passes; acceptance test_completion_verification_exhausted_registered (scripts/plan_corpus/tests/test_exit_reasons.py) asserts the member is in CANONICAL_EXIT_REASONS with its routing row.
  • Add the GENUINE member soak_nonconvergence to rules.HaltReason (the §06.5 soak-node true-non-convergence target) with autopilot_disposition: structured_exit; it is in GENUINE (never CURABLE — a genuinely non-converging route has no trustworthy auto-cure), and its disposition is structured_exit so the engine emits exit state for the caller orchestrator + records the non-convergence fingerprint to active-plan HISTORY, never an interactive prompt in autopilot. Its autopilot_disposition parity is asserted by test_soak_nonconvergence_autopilot_disposition (§06.5) and by the §06.1 test_halt_reason_partition_exhaustive (every GENUINE member carries a disposition). Because route_walk emits it as an exit_reason, it is ALSO registered in scripts/plan_corpus/exit_reasons.py CANONICAL_EXIT_REASONS + an EXIT_REASON_ROUTING row (mirroring the no_cross_plan_ready_node registration) so the §06.3 test_route_walk_exit_reason_parity subset check passes; acceptance test_soak_nonconvergence_registered (scripts/plan_corpus/tests/test_exit_reasons.py) asserts the member is in CANONICAL_EXIT_REASONS with its routing row.
  • Subsection close (06.1) — all [x]; status: complete.

06.2 — cure_dispatch.py (consolidation)

  • Author scripts/plan_orchestrator/cure_dispatch.py (ABSENT today). Single registry: dispatch(halt_reason, ctx) -> CureResult. Consolidate per the Pass 2 §6 map: deadlock_cure_dispatch, schema_cure_dispatch, autopilot_auto_cure (target-self + redispatch shapes), auto_cure.execute_cures (drift SCRIPT_AUTO), auto_cure_loop LLM path, materiality, linear_execution_cure_dispatch, review_blocked_cure_dispatch. The consolidation MUST be EXHAUSTIVE: linear_execution_cure_dispatch + review_blocked_cure_dispatch carry an identical _compose_resume_bash argv-splitter to the three already named — leaving any of them on disk after this node closes is LEAK:algorithmic-duplication (the single-registry design is violated by a surviving sibling splitter). Acceptance: test_cure_dispatch_no_residual_splitter asserts that after consolidation NO module under scripts/plan_orchestrator/ defines a _compose_resume_bash/compose_resume_bash other than the one shared util in cure_dispatch.py (grep-equivalent AST scan over the engine surface), so a re-introduced duplicate fails the test.
  • Extract ONE shared compose_resume_bash(argv, inject_flags, strip_flags) util (Pass 2 risk 7.1/7.8 — three divergent argv-splitters today). Test matrix: no prior flags / one prior flag / stacked duplicates.
  • Preserve per-cure acknowledgment paths as first-class registry fields (Pass 2 risk 7.2 — drift-hash vs prior_schema_blocking.json vs cure_applied.json are NOT uniform). Carry cap_exceeded + full audit_result in the cure context (risks 7.3/7.4). Consume DRIFT_CLASSES by reference, never re-register (risk 7.6).
  • Pin halt_history.py owner (cross-cutting cc-compose-resume-bash-shared-util / Pass 2 risk 7.5 — placement was undecided): halt_history.py lives at scripts/plan_orchestrator/halt_history.py (the orchestrator engine surface — it is cross-session halt-convergence state the §06.5 soak node consumes, NOT a commit_push-domain concern). It exposes a READ-ONLY query interface (query_recent_halts(node_id, window), convergence_signal(node_id)) and is written ONLY by the route_walk halt-recording path. It MUST NOT import from scripts/commit_push/ or from scripts/plan_orchestrator/shared/ commit-domain modules (avoids the cross-domain coupling risk 7.5). Acceptance: test_halt_history_import_boundary (tests/test_halt_history.py) — AST/import scan asserts halt_history.py imports NO scripts.commit_push.* symbol and exposes the query interface; a re-introduced commit_push coupling fails the test (LEAK:scattered-knowledge).
  • Engine NEVER emits action: halt for a CURABLE reason; GENUINE → surface via the member’s autopilot_disposition; USER_DECISION → AskUserQuestion in INTERACTIVE mode ONLY. In AUTOPILOT mode (per skill-control-contract.md §Autopilot Mode), a USER_DECISION member NEVER reaches an AskUserQuestion — the engine routes it through structured_exit (emit exit state for the caller orchestrator to route) and records the disposition to active-plan HISTORY, never an interactive prompt. Each USER_DECISION member therefore declares BOTH an interactive_disposition: ask_user AND an autopilot_disposition ∈ {structured_exit, log_and_continue}; the engine selects by execution mode. Acceptance: test_user_decision_no_autopilot_askuser (in tests/test_cure_dispatch.py) drives every USER_DECISION member through dispatch(reason, ctx) with ctx.mode == "autopilot" and asserts the returned CureResult carries NO AskUserQuestion action — only structured_exit or log_and_continue — proving zero-halt INV-7 holds in autopilot (a USER_DECISION never blocks the walk on a prompt the autopilot user is not present to answer).
  • Subsection close (06.2) — all [x]; status: complete.

06.3 — route-walk node

  • Author scripts/plan_orchestrator/route_walk.py: single next_action entry consuming §05 cross-plan merge; sole caller of gates + serve_next + cure_dispatch. Subsumes roadmap.py’s internal step chain. Locked boundary: no other module orchestrates the walk.
  • roadmap.py → route_walk migration boundary (ar-roadmap-route-walk-migration — route_walk subsumes scripts/plan_orchestrator/roadmap.py’s step chain but the ~106 import references across scripts/plan_orchestrator/cli.py, scripts/review_plan_runtime/review_plan.py, the commit_push dispatch path, and 30+ tests must be re-pointed before roadmap.py can be deleted): §06.3 AUTHORS route_walk.py and makes it the SOLE walk orchestrator, but does NOT delete roadmap.py at §06 close. A backward-compat SHIM WINDOW precedes deletion: at §06.3 close, roadmap.py’s public entry points (roadmap, the Step-1 resume-pointer + _build_next_unblocked surface) become THIN DELEGATES that forward to route_walk.py (no second walk implementation survives — roadmap.py holds zero orchestration logic, only the delegating signature so existing imports keep resolving). The shim is the SSOT-preserving bridge: one walk implementation (route_walk.py), one set of import names (roadmap.py delegates) during the migration. Full deletion of roadmap.py + re-pointing all ~106 import references to route_walk.py is DEFERRED to §11A strip-skills, which owns the orchestrator markdown-walk + dead-import removal sweep (roadmap.py is scripts/plan_orchestrator/, the CONSUMER/skill side — removed when the skills go v7-only, before §11B strips the plan_corpus parsers); §11A’s deliverable list adds roadmap.py deletion + import re-point (forward reference — §11A tracks it; §06 close-out does not gate on §11A). Acceptance (§06.3 scope): test_roadmap_delegates_to_route_walk (tests/test_route_walk.py) asserts roadmap.py’s entry point invokes route_walk.serve_next/the route_walk walk surface and defines NO independent serve_next/step-chain of its own (AST scan — a surviving second walk impl fails the test, LEAK:algorithmic-duplication). §11A-scope deletion is verified by §11A’s dead-import sweep, not a §06 gate.
  • INV-18 (per decisions/02-content-as-context-unit.md): the next_action payload hands the LLM the WHOLE body_ref content file (inlined content OR its path for a full Read) as the bounded task — NO section_info-style fragment, summary, or structural slice in the payload. The whole content file is the node’s sole context unit.
  • exit_reason→next_action parity: route_walk maps EVERY exit_reason it can emit (CURABLE → cure_dispatch re-engage; GENUINE → the member’s autopilot_disposition from §06.1; USER_DECISION → interactive_disposition: ask_user in interactive mode, autopilot_disposition from §06.2 in autopilot mode — NEVER an AskUserQuestion in autopilot) to a concrete next_action. Acceptance: test_route_walk_exit_reason_parity (in scripts/plan_orchestrator/tests/test_route_walk.py) anchors on the existing closed-enum SSOT — CANONICAL_EXIT_REASONS + EXIT_REASON_ROUTING in scripts/plan_corpus/exit_reasons.py — and asserts the set of exit_reasons route_walk emits is a subset of CANONICAL_EXIT_REASONS, with each routed via its EXIT_REASON_ROUTING row, so no exit_reason can reach a caller without a declared next_action (cures the §06.3-re-owns-caller→exit_reason-routing claim covering BUG-07-112). halt_reasons.py (§06.1) adds ONLY cure/disposition metadata ATOP this canonical set — never a duplicate exit_reason authority (avoids LEAK:scattered-knowledge).
  • INV-19 single-ready-node assertion (per references/restructure-charter-seed.md §2 INV-19): route_walk.serve_next(plan) MUST return at most ONE ready node per call (the deterministic next-in-lexorank-order unblocked node). Add a runtime assertion + a regression test: assert len(ready_nodes) <= 1, 'INV-19 violation: strict-linear-single-branch DAG cannot have multiple ready nodes'. Multiple-ready-node case is structurally impossible IF the §03.1 schema rejects branch fields; the assertion is defense-in-depth. Acceptance: test_route_walk_single_ready_node (in scripts/plan_orchestrator/tests/test_route_walk.py) constructs a fixture plan and asserts serve_next never emits >1 ready node; a synthetic branch-fixture (constructed bypassing the schema) trips the assertion deterministically. serve_next is deterministic by construction — never a routing choice.
  • INV-20 serve_next semantics (per references/restructure-charter-seed.md §2 INV-20): route_walk.serve_next(plan) performs a linear scan in lexorank order; returns the FIRST not-started node whose predecessors are ALL done (verified via completion.gates_verified non-empty per §03.1). A predecessor is BLOCKING unless it is done-with-attestation — both in-progress AND in-review count as not-yet-done (an in-review predecessor has NOT written its completion.gates_verified via the §06.4 choke point, so a successor reaching it would crawl forward past unverified work — the exact INV-20 violation). If the scan encounters a NON-done predecessor (in-progress OR in-review), return THAT node (caller resumes / finishes its review) — NEVER skips past it as an alternative. The §40 relocate primitive handles cases where a section blocks; the engine NEVER uses skip-past-non-done as a substitute. Runtime assertion: assert not (returned_node.status == "not-started" and any(p.status in ("in-progress", "in-review") for p in predecessors(plan, returned_node))). Regression test test_serve_next_never_skips_in_progress (in scripts/plan_orchestrator/tests/test_route_walk.py) constructs THREE fixtures: (1) predecessor in-progress, successor not-startedserve_next returns the predecessor; (2) predecessor in-review, successor not-startedserve_next returns the predecessor (in-review is blocking, not skippable); (3) predecessor done with non-empty gates_verified, successor not-startedserve_next returns the successor.
  • Parser-SSOT reuse: route_walk + serve_next consume the §03/§03A substrate parser SSOT (scripts/plan_corpus/migrations/006_md_to_json.py:build_plan_json_from_dir + the §03 per_plan_route surface) for any plan.json/content parse; the engine defines NO second md→dict parser or frontmatter parser. Acceptance: test_route_walk_reuses_parser_ssot (tests/test_route_walk.py) — AST scan over scripts/plan_orchestrator/ asserts no sibling build_plan_json_from_dir/frontmatter parser; a re-implementation fails (LEAK:algorithmic-duplication).
  • Output determinism: route_walk.serve_next + the emitted next_action envelope are byte-identical across repeated runs on unchanged plan.json + git HEAD; inputs are corpus + HEAD only (no time.time()/uuid/random/session-state), mirroring resume_manifest per state-discipline.md §6.5. Acceptance: test_route_walk_output_determinism (tests/test_route_walk.py) — asserts byte-identical next_action JSON across repeated in-process, in-process-vs-CLI, and fresh-process-vs-continuous-process calls.
  • Malformed-plan.json error path (fail-loud, never silent-skip): a plan.json failing schema validation raises the typed schema_invalid halt_reason (CURABLE → §06.2 schema_cure_dispatch); the engine NEVER silent-skips the malformed plan and NEVER returns a ready node from the corrupt corpus. Acceptance: test_route_walk_malformed_plan_json_raises (tests/test_route_walk.py) — feeds a malformed plan.json fixture; asserts the typed error / schema_invalid cure route, never a ready node.
  • Engine bootstrap + empty-route / all-blocked exit_reason (architectural-risk ar-no-cross-plan-ready-node-registration + cc-engine-bootstrap-empty-corpus — the §05→§06 handoff yields no ready node when every cross-plan node is blocked/deferred OR the corpus is fully done; route_walk must cold-start, merge, and resolve these terminal states via a canonical exit_reason, never crash or emit a spurious ready node): route_walk’s cold-start path performs (1) first-route discovery (locate the first route plan with a plan.json), (2) cold-start cross-plan merge (merge all per-plan nodes by the §05 (key, plan, id) comparator with no prior session/cache state — determinism per test_route_walk_output_determinism), and (3) all-nodes-done terminal resolution. Register no_cross_plan_ready_node in scripts/plan_corpus/exit_reasons.py CANONICAL_EXIT_REASONS + add its EXIT_REASON_ROUTING row with caller_action: log_and_skip, exit_code: 0 (a clean terminal state — an empty unblocked frontier is NOT an error, NOT a halt). route_walk.serve_next emits no_cross_plan_ready_node when the lexorank scan finds zero not-started nodes with all-done predecessors AND no NON-done blocking predecessor to return (i.e. the corpus is fully done/abandoned, freshly empty, or every remaining node is cross-plan-deferred). Acceptance: test_no_cross_plan_ready_node_registered (scripts/plan_corpus/tests/test_exit_reasons.py) asserts the reason is in CANONICAL_EXIT_REASONS with the log_and_skip/exit_code 0 routing row; test_route_walk_empty_corpus_emits_no_ready_node + test_route_walk_all_deferred_emits_no_ready_node (tests/test_route_walk.py) feed (a) an empty corpus (cold-start bootstrap with no nodes) and (b) an all-cross-plan-deferred corpus and assert serve_next emits no_cross_plan_ready_node (exit_code 0) and returns NO ready node — never raising, never an action: halt; test_route_walk_cold_start_first_route_discovery asserts a cold-start (no cache) discovers the first route plan and merges cross-plan nodes deterministically.
  • INV-15 separation on resolve: route_walk CONSUMES the §05.3 flat-node group labels (proposal/architectural/phase-local/bug) for filtering/grouping ONLY; ordering comes from key, identity from id, never from group. The engine is a CONSUMER of the §05 route model’s group labels, never an owner of routing status. Acceptance: test_route_walk_preserves_inv15_separation (tests/test_route_walk.py) — asserts serve_next ordering is invariant under group-label permutation and no engine path writes a group value as a routing-status field. Per references/restructure-charter-seed.md §2 INV-15 + §05.3.
  • Subsection close (06.3) — all [x]; status: complete.

06.4 — review-as-phase + bugs-as-nodes

  • review-as-phase: a node isn’t done until its review node passes; auto-dispatch reviewers, auto-triage, cure-and-re-engage on findings; review state = routing fields on the node; no human halt (refinement / R6Q22).
  • INV-17 single verified-completion choke point (per decisions/01-completion-integrity-invariants.md): review-as-phase is the SOLE writer of done. Before flipping a node to done it runs deliverable-existence verification (declared body_ref/touch paths exist on disk, declared tests pass, no pending-bearing tracking rows) and writes the §03 completion attestation (body-bound hash). Verification FAILS CLOSED: on any missing deliverable the node does NOT complete and does NOT halt — it routes to quarantine (relocate back to not-done) + records which criterion failed. No other engine path may write done. Acceptance: test_verified_completion_choke_point (tests/test_review_phase.py) — asserts only one path writes done, only post-verification, and a deliverable-absent node routes to quarantine not done/halt.
  • INV-20 sole writer of completion.gates_verified (per references/restructure-charter-seed.md §2 INV-20): review-as-phase is the SOLE writer of the completion.gates_verified: [str] array introduced by §03.1. It populates the list with the named-skill gates that ran to exit_reason: clean for this section’s code surface (e.g., tpr-review-code-side, pytest-<suite-name>, plan-corpus-check). Empty list → §03.1 schema rejects status: done (force-flip via legacy paths impossible at write-time). The gate-name set is declared per-section by the section’s gates_required: [str] frontmatter (see §06.4 deliverable-existence verification — gates_required is one of the declared criteria); the choke point asserts set(gates_required) ⊆ set(completion.gates_verified) before flipping done. No cure path, route-walk, or serve_next may write completion.gates_verified directly. Acceptance: test_gates_verified_sole_writer (tests/test_review_phase.py) — asserts review-as-phase is the SOLE writer of completion.gates_verified and that gates_required ⊆ gates_verified is enforced before done.
  • INV-20 gates_required schema owner (blind-spot bs-gates-required-owner — the subset check gates_required ⊆ gates_verified has no schema-backed owner today): add gates_required: list[str] to scripts/plan_corpus/schemas.py PlanSectionSchema (optional, default []) as the SOLE schema owner of the per-section required-gate declaration; the field validates as a list of known gate names drawn from the same gate-name vocabulary completion.gates_verified is populated from (tpr-review-code-side, pytest-<suite>, plan-corpus-check, …). An unknown gate name in gates_required fails schema validation (schema_invalid → §06.2 schema_cure_dispatch). The §06.4 choke point reads gates_required from this validated field — NEVER an ad-hoc inline list. Acceptance: test_gates_required_schema_owner (in scripts/plan_corpus/tests/test_schemas.py) asserts (a) a valid gates_required list passes validation, and the NEGATIVE case test_gates_required_rejects_unknown_gate asserts a gates_required entry naming an unknown gate raises a schema-validation error — so a typo’d or invented gate name cannot silently weaken the subset check before §06.4 enforces gates_required ⊆ gates_verified.
  • Quarantine retry cap (prevents the pick → verify-fail → quarantine → re-pick livelock): the choke point records a verification_fail_count on the node (in the node’s content tracking, NOT a plan.json field per INV-3). After N consecutive failed verifications of the SAME node (default N=3, declared in the engine config), the node escalates from quarantine (re-routable) to the GENUINE halt completion_verification_exhausted with autopilot_disposition: log_and_continue — the node is set aside (route relocates past it per the plan-scoped linear walk, so one stuck node never deadlocks the corpus) and the exhaustion is recorded to active-plan HISTORY. The reset trigger is a CHANGE to the node’s declared deliverable set — NOT merely a markdown-content edit (a content-only edit would miss the CODE deliverables a code-bearing node fails verification on). The choke point computes a deliverable_fingerprint = hash over the (path, mtime) pairs of EVERY declared touches: / body_ref deliverable (code files AND content files) EXCLUDING the node’s own verification_fail_count content-tracking file — that file is the engine’s retry-budget bookkeeping, not a deliverable; including it would make every failed-verification write (which bumps verification_fail_count, changing that file’s mtime) flip the fingerprint and reset the budget to 0 on the very next attempt, a livelock where the retry cap never accumulates. The fingerprint set is set(touches: ∪ body_ref) - {verification_fail_count_tracking_path}. verification_fail_count resets to 0 ONLY when the current fingerprint (over the excluded set) differs from the one stored at the last failed verification. This way editing the CODE that failed verification (not just the tracking markdown, and never the budget file itself) is what re-arms the retry budget. Acceptance: test_quarantine_retry_cap asserts the (N+1)th verify-fail escalates and that route_walk relocates past the exhausted node without halting (proving the cap actually accumulates across attempts — the budget file’s own mtime churn does NOT reset it); test_quarantine_reset_on_deliverable_change asserts that touching a declared CODE deliverable (changing its mtime) resets verification_fail_count while a no-op re-verify with an unchanged fingerprint does NOT reset (so a content-only edit that leaves the failing code untouched does not falsely re-arm); the NEGATIVE test_quarantine_fingerprint_excludes_budget_file asserts the verification_fail_count tracking file is NOT in the fingerprint set, so writing it cannot reset the budget.
  • Invariant-acceptance-hook gate (delivers §01.1 success_criterion #3): as part of the deliverable-existence verification above, the choke point invokes the existing scripts/plan_corpus/cross_section_check.py STRUCTURE:invariant-acceptance-hook-missing detector for the completing node’s owning invariants (per §01.1’s invariant→section(s) table); an unproven acceptance hook FAILS CLOSED identically — node routes to quarantine, never done, never action: halt (INV-7). This is the mechanized contradiction-check that replaces the human ‘reviewers flag’ backstop. Dependency note: the detector module ALREADY EXISTS at scripts/plan_corpus/cross_section_check.py; §06.4 CONSUMES it (and extends it for any §06.4-specific detector additions per the checkbox below) — it does NOT author a new module. §12.1 soak also CONSUMES the same detector as a corpus-wide invariant-coverage assertion. No backward dependency on §12; the detector exists by the time §06 closes (§06 depends_on [05]; §03 reachable transitively via §05 → §04 → §03A → §03).
  • Detector authoring-vs-consuming boundary (explicit): §06.4 is the SOLE AUTHOR of any §06.4-specific detector additions to scripts/plan_corpus/cross_section_check.py (route-node owning-invariant lookups against §01.1’s invariant→section table). §06.4 AUTHORS + REGISTERS these additions BEFORE its choke-point gate CONSUMES them — authoring precedes consumption within this node, no forward dependency. §12.1 soak is AGGREGATE-ONLY: it CONSUMES the detector (already authored + registered by §06.4) as a corpus-wide invariant-coverage assertion and AUTHORS no detector logic of its own. There is NO backward dependency from §06.4 onto §12 (§12 depends_on: [..., 06]; a predecessor never consumes a successor’s output). The detector exists by the time §06 closes because §06.4 authored it; §12 only reads it. Acceptance covered by cross_section_check.py self-test (tests/test_cross_section_check.py); a §12-side aggregate assertion that tried to ADD detector logic would be a §12 scope violation, not a §06.4 gap.
  • bugs-as-nodes: bug plans (JSON-first via §10) merge into the cross-plan route; /add-bug mints a node + key; a bug blocking work is a hint_needs; /fix-bug is the walker serving the bug node (R6Q21).
  • subsumption relationship (per decisions/03-plan-bug-subsumption-absorption.md, absorbs plan-bug-subsumption): a bug whose fix is a CONSEQUENCE of an umbrella node carries a hint_needs on the umbrella and relocates to serve AFTER it (consequence, NOT prerequisite — the inverse of a blocker). When the umbrella reaches the §06.4 verified-completion choke point, deliverable verification runs the bug’s verification_test (reuse INV-17 deliverable-existence machinery): PASS → the bug node completes by construction (its non-reproduction IS its deliverable); FAIL → un-subsume = route the bug node to quarantine (relocate back to active route), never auto-completed, never action: halt (zero-halt INV-7). Un-subsume is NOT triggered by umbrella quarantine alone: an umbrella that quarantines (re-routable, may still re-cure and complete) RETAINS its subsumed bugs’ hint_needs — dropping the hint on a transient quarantine would relocate the bug node back to the active route and execute it as an INDEPENDENT incomplete node before the umbrella (its consequence-source) has completed, the premature-execution failure mode. The hint_needs (serve-after relationship) is removed ONLY on EXPLICIT umbrella ABANDONMENT (the umbrella node is marked abandoned/superseded, never to complete) OR on the bug’s OWN verification-fail at the umbrella’s verified-completion choke point. A quarantined-but-still-live umbrella keeps its subsumed bugs parked behind it. The subsumption claim + 3-signal evidence (replaced_subsystem / root_cause_pointer / verification_test_pointer) are authored in the umbrella node’s content (INV-18) and re-validated at review-as-phase sign-off — never mechanically inferred, never a plan.json field (INV-3).
  • Subsumed-bug gates_verified exemption (bs-subsumed-bug-gates-verified — INV-20 requires non-empty completion.gates_verified for status: done, but a subsumed bug node completes BY CONSTRUCTION at the umbrella’s choke point where non-reproduction IS the deliverable, so it runs no named-skill gates of its own and would have an empty gates_verified that §03.1 rejects): when the §06.4 choke point completes a subsumed bug node by construction (the umbrella’s deliverable-verification confirmed the bug’s verification_test passes), it AUTO-POPULATES that bug node’s completion.gates_verified with the single canonical gate name subsumption-verified-by-umbrella:<umbrella-id> — a real, schema-known gate-name token (added to the gates_required/gates_verified vocabulary in §03.1) recording that the bug’s verification ran AS PART OF the umbrella’s choke point, not as an independent gate run. This keeps gates_verified non-empty (INV-20 schema holds — no exemption carve-out that would weaken the impossible-state) while truthfully attributing the verification to the umbrella. review-as-phase remains the SOLE writer of the field (the umbrella’s choke point IS review-as-phase). A subsumed bug node NEVER reaches done with an empty gates_verified and NEVER reaches done via any path other than the umbrella’s choke point. Acceptance: test_subsumed_bug_gates_verified_autopopulated (in tests/test_review_phase.py) asserts a completed-by-construction subsumed bug node carries completion.gates_verified == ["subsumption-verified-by-umbrella:<umbrella-id>"] (non-empty, schema-valid) and that the §06.4 choke point — not serve_next or cure_dispatch — wrote it.
  • Review-as-phase node loads the relevant /improve-tooling design-log §4 Lessons + §6 Improvement Log (+ list-locked-designs for touched paths) as a mandatory grounding input before a section’s review can sign off (INV-16); the consultation is recorded on the node, and review cannot reach done without it.
  • INV-18 content-size gate (per decisions/02-content-as-context-unit.md): review-as-phase runs the §03 content-size lint; an over-cap content/<id>--*.md blocks done and routes to a SPLIT cure. The split has TWO separated responsibilities that never blur: (1) the engine/route-API mints sibling flat nodes (new ids + lexorank keys between neighbors) and writes plan.json routing — purely mechanical, no content awareness; (2) the LLM (a bounded route node the engine serves) partitions the over-cap body across the minted siblings at semantic boundaries (never splitting a checklist row or a fenced code block mid-block) and writes ONLY markdown content files — never plan.json. The engine never mechanically text-splits the body (a byte-offset split would break checklist/code-block boundaries); the LLM never mints nodes or writes routing. Never compaction-into-denser-prose. The split is a routing op handled through §06.2 cure_dispatch (quarantine-adjacent: the node does not reach done while over-cap; the cure is “split,” not “acknowledge”). Acceptance: test_split_cure_responsibility_separation asserts the node-mint path touches only plan.json and the content-partition task injects only markdown content paths, with no path that both mints a node and authors content.
  • Subsection close (06.4) — all [x]; status: complete.

06.5 — path-scoped-commit + soak

  • path-scoped-commit node: §06.5 owns ONLY the route-side capability interface — the engine’s call contract (invoke_commit(touches, scope) -> CommitResult) plus an acceptance test that exercises it against a MOCKED commit backend (test_commit_capability_interface asserts the engine routes to the commit capability with the node’s touches: scope and consumes the result, with the backend stubbed). The actual compute_scope_restriction wiring lives in §07 (which depends_on: [06]); §06.5 reaches done against the mock and MUST NOT depend on §07’s wiring to close (a successor cannot gate a predecessor’s completion — INV topological invariant). §07 wires the real backend behind the same interface.
  • Pin the invoke_commit / CommitResult contract shape (blind-spot bs-commitresult-contract-shape — §07 wires the real backend behind the same interface and must not guess the boundary): invoke_commit(touches: list[str], scope: CommitScope) -> CommitResult where CommitResult is a typed dataclass in scripts/plan_orchestrator/commit_capability.py carrying {ok: bool, commit_sha: str | None, halt_reason: str | None, error_payload: dict | None}ok=Truecommit_sha populated + halt_reason/error_payload None; ok=Falsecommit_sha None + halt_reason set to a categorized commit_push halt string (per §06.1 non-enum partition) + error_payload carrying the /commit-push envelope’s halt_reason/failing_repo/scope fields. The mock backend in test_commit_capability_interface returns BOTH an ok=True and an ok=False CommitResult so the engine’s consume-path is exercised on both; §07’s real backend (scripts/commit_push/ wiring) implements the SAME CommitResult shape with no field additions. Acceptance: test_commit_result_contract_shape (tests/test_commit_capability.py) asserts the CommitResult dataclass fields + the ok/not-ok field-population invariants above, so §07 wires the real backend against a pinned contract.
  • Commit-failure zero-halt disposition (blind-spot bs-commit-failure-disposition + bs-commit-failure-quarantine-not-continue / INV-7 — an unhandled CommitResult.ok=False could autopilot-halt on a routable condition, AND a log_and_continue disposition would advance to a SUCCESSOR node while THIS node’s cures sit uncommitted in the working tree, breaking change isolation and cascading the dirty tree into the next node’s commit scope): the engine NEVER emits action: halt on a commit failure AND NEVER advances the route past a node whose cures are uncommitted. A CommitResult with ok=False carries a categorized halt_reason (a commit_push halt string per §06.1); §06.2 cure_dispatch routes it to quarantine — the node relocates back to not-done (per the plan-scoped linear walk so one stuck node never deadlocks the corpus) and stays the route’s responsibility until its cures commit cleanly, NEVER to log_and_continue (which would crawl forward past the uncommitted tree). The commit_push halt strings are therefore GENUINE-with-disposition quarantine (re-routable), NEVER CURABLE (the engine does not silently re-attempt a commit a hook rejected) and NEVER log_and_continue (advancing past an uncommitted node is the change-isolation break this blind-spot names). When the §06.4 quarantine retry cap is hit (the same node’s commit fails N consecutive times), the node escalates to the GENUINE completion_verification_exhausted (autopilot_disposition: log_and_continue) — at THAT escalation point the working tree’s uncommitted cures are recorded to active-plan HISTORY and the route relocates past the exhausted node, never before. The disposition is recorded to active-plan HISTORY on every quarantine, never an interactive prompt in autopilot. Acceptance: test_commit_failure_zero_halt_disposition (tests/test_commit_capability.py) drives a mocked ok=False CommitResult through the engine consume-path with ctx.mode == "autopilot" and asserts the engine routes to quarantine (relocates the node back to not-done, does NOT advance to a successor) and emits NO action: halt and NO AskUserQuestion; the paired test_commit_failure_does_not_advance_route asserts serve_next does NOT return a SUCCESSOR node while the committing node’s cures are uncommitted (the quarantined node or its predecessor is returned, never the next-in-key successor) — closing the INV-7 zero-halt gap AND the change-isolation gap for the commit capability.
  • soak node: cross-invocation convergence monitor (consolidate redispatch_loop_detector + halt_history cross-session + acknowledgment); emits the named GENUINE halt soak_nonconvergence only on true non-convergence (a node whose halt-history convergence_signal shows the same halt fingerprint recurring past the soak window with no forward progress — distinct from transient redispatch, which is NOT a halt); feeds §12 soak verification. The soak_nonconvergence halt_reason is added to rules.HaltReason in §06.1 with autopilot_disposition: structured_exit (a genuinely non-converging route has no trustworthy auto-cure — the engine emits exit state for the caller orchestrator and records the non-convergence fingerprint to active-plan HISTORY, never an action: halt mid-walk, never an interactive prompt in autopilot). Acceptance: test_soak_convergence_monitor asserts a true non-convergence emits soak_nonconvergence while transient redispatch does NOT; the paired test_soak_nonconvergence_autopilot_disposition asserts soak_nonconvergence ∈ GENUINE carries autopilot_disposition: structured_exit and that driving it through cure_dispatch.dispatch("soak_nonconvergence", ctx) with ctx.mode == "autopilot" returns a structured_exit CureResult with NO AskUserQuestion and NO action: halt.
  • Low-confidence-absorb falsifiable-reopen fallback (soak-fed; the EXECUTABLE reproduction assertion is IMPLEMENTED + OWNED by §12 where the soak tests live, NOT a §06 close-out gate — §06 ships only the soak DATA feed, not the local verification, so §06 close-out never depends on the not-started §12): §06.5’s deliverable here is the soak-node convergence-monitor feed (above) that EMITS the per-absorb non-reproduction signal §12 consumes; the executable falsifiable-reopen assertion belongs to §12. §12 soak (tests/test_soak.py in §12 scope) asserts each low-confidence absorb’s original symptom does NOT reproduce on a concrete trigger — BUG-07-095: drive a node complete then run a doc_sync pass; assert no co-flip back to in-progress (cure_dispatch terminal-state coherence §06.2 holds). BUG-07-108: drive a section through /review-plan close-out then a follow-up scan; assert reviewed: true survives (review-as-routing-field §06.4 holds). If EITHER symptom reproduces, the absorb is FALSE: §12 soak reopens that bug as a separate route node (/add-bug mints it per §06.4 bugs-as-nodes) with the reproduction trigger as its verification_test, and §06’s absorbed-defects table does not claim it resolved. §06 closes on its own local acceptance tests (§06.N) and the soak-feed deliverable; the §12 reproduction assertion is a §12 success criterion (a predecessor never gates on a successor — §12 depends_on: [..., 06]).
  • Subsection close (06.5) — all [x]; status: complete.

Absorbed defects (bug-tracker triage 2026-05-26)

These standalone tracker bugs are subsumed by §06’s zero-halt route-walk + cure_dispatch.py + review-as-phase + bugs-as-nodes (the halting machinery — roadmap.py / pivot.py / markers.py / plan-complete.py focus-picker — is deleted/replaced). This section’s deliverable MUST resolve each; the tracker entries are closed obe-via-absorb pointing here.

BugSymptom subsumed
BUG-07-077autopilot fixed-point loop on NN.R findings (PLAN_SCOPE_DEADLOCK → cured node §06.1)
BUG-07-082autopilot halts on stale review_pipeline markers (marker concept retired §05.2; route_walk reader)
BUG-07-093routing cycles when in-progress + all checkboxes flipped (status derived from id-scan §03.2)
BUG-07-095doc_sync_drift co-flip complete→in-progress (cure_dispatch terminal-state coherence §06.2) — low-confidence absorb
BUG-07-101pivot self-loop deadlock (TARGET_SELF_DRIFT / REDISPATCH_LOOP → CURABLE §06.1)
BUG-07-102next_action schema rejects chain_diagnosis.exclusion_attempt (route_walk single next_action)
BUG-07-103unreviewed_plan auto-picker re-loops (auto-picker replaced by route_walk §06.3)
BUG-07-107misroutes positional plan dir + picks blocked subsection (serve_next §05.1)
BUG-07-108/review-plan close-out reviewed:true reverts (review = routing field §06.4) — low-confidence absorb
BUG-07-122focus_picker_internal halt on complete + reviewed:false (review-as-phase §06.4)
BUG-07-124focus-picker halts on complete + reviewed:false + blocked_by:[BUG] (bugs-as-nodes §06.4)
BUG-07-112tp-help caller_exit_reason_handlers are flat exit_reason lists with no per-reason action/autopilot routing — route_walk re-owns caller→exit_reason routing (§06.3)

Low-confidence absorb fallback (falsifiable)

  • The two low-confidence absorbs (BUG-07-095, BUG-07-108) are subsumed by the cure_dispatch terminal-state-coherence redesign (§06.2) and the review-as-routing-field redesign (§06.4).
  • §06.5 ships the soak-node convergence-monitor DATA FEED that emits each absorb’s non-reproduction signal; the EXECUTABLE falsifiable-reopen assertion is implemented + owned by §12 (tests/test_soak.py, §12 scope), which checks BUG-07-095 / BUG-07-108 non-reproduction and reopens each via /add-bug on reproduction.
  • §06 close-out does NOT gate on §12 — a predecessor never gates on a successor (§12 depends_on includes §06).

06.R Third Party Review Findings

  • None.

06.N Completion Checklist

  • 06.1-06.5 [x] and status: complete.
  • All success criteria have [x] checkboxes.
  • test_cure_dispatch_registry green (every halt_reason categorized; no unregistered cure); halt_emission_lint clean (no new action: halt for CURABLE).
  • Per-capability acceptance tests green (one named test + the invariant it proves per node):
NodeAcceptance test (file)Invariant proven
06.1 halt_reasons.pytest_halt_reason_partition_exhaustive + test_gate_internal_error_is_genuine_carveout (tests/test_halt_reasons.py)every rules.HaltReason member is categorized exactly once + every GENUINE member has an autopilot_disposition (INV-6 zero-halt categorization complete); gate_internal_error is the single GENUINE harness-malfunction carve-out reconciling GENUINE with zero-halt INV-7 (autopilot_disposition: structured_exit)
06.2 cure_dispatch.pytest_cure_dispatch_registry + test_compose_resume_bash_matrix + test_cure_dispatch_no_residual_splitter + test_user_decision_no_autopilot_askuser (tests/test_cure_dispatch.py)every CURABLE halt_reason has a registered cure; no action: halt for CURABLE; shared resume-bash util handles no/one/stacked prior flags (INV-6, Pass 2 risk 7.1/7.8); NO surviving _compose_resume_bash sibling on disk after consolidating linear_execution/review_blocked (LEAK:algorithmic-duplication closed); every USER_DECISION member routes through structured_exit/log_and_continue in autopilot with NO AskUserQuestion (zero-halt INV-7)
06.3 route_walk.pytest_route_walk_exit_reason_parity + test_serve_next_never_skips_in_progress + test_route_walk_reuses_parser_ssot + test_route_walk_output_determinism + test_route_walk_malformed_plan_json_raises + test_route_walk_preserves_inv15_separation + test_no_cross_plan_ready_node_registered + test_route_walk_empty_corpus_emits_no_ready_node + test_route_walk_all_deferred_emits_no_ready_node + test_route_walk_cold_start_first_route_discovery + test_roadmap_delegates_to_route_walk (tests/test_route_walk.py)every emitted exit_reason maps to a concrete next_action; whole-body_ref injection carries no fragment (INV-18 + caller→exit_reason routing, BUG-07-112); strict-forward serve_next never skips past an in-progress OR in-review predecessor (both blocking — INV-20); engine reuses the §03 parser SSOT (no 2nd parser); next_action output is byte-deterministic; a malformed plan.json fails loud via schema_invalid (never silent-skip); INV-15 separation preserved — ordering from key, identity from id, group non-ordering; engine bootstrap + empty/all-deferred corpus emits no_cross_plan_ready_node (exit_code 0, never a halt) and cold-start discovers the first route plan deterministically; roadmap.py is a thin delegate to route_walk (no second walk impl survives — §11A owns full deletion)
06.4 review-as-phasetest_verified_completion_choke_point + test_quarantine_retry_cap + test_quarantine_reset_on_deliverable_change + test_split_cure_responsibility_separation + test_gates_verified_sole_writer (tests/test_review_phase.py)only one path writes done and only post-verification; verify-fail routes to quarantine not done/halt; N-fail escalation relocates past the node; verification_fail_count resets ONLY on a declared-deliverable mtime-fingerprint change (CODE not just markdown), never on a no-op re-verify; split-cure keeps node-mint (engine/plan.json) and content-partition (LLM/markdown) separate; review-as-phase is the SOLE writer of completion.gates_verified and asserts gates_required ⊆ gates_verified before flipping done (INV-17 + INV-18 + INV-20)
06.4 bugs-as-nodes / subsumptiontest_subsumption_completes_by_construction + test_unsubsume_on_verification_fail + test_subsumed_bug_retains_hint_on_quarantine (tests/test_review_phase.py)a subsumed bug completes ONLY when the umbrella’s choke point confirms its verification_test; verification-fail un-subsumes via quarantine; a transient umbrella quarantine RETAINS the bug’s hint_needs (no premature execution) — the hint drops ONLY on explicit umbrella abandonment or the bug’s own verification-fail (INV-14)
06.4 invariant-acceptance-hookcross_section_check.py self-test (tests/test_cross_section_check.py)an owning-invariant node with no acceptance hook FAILS CLOSED → quarantine (INV-7; existing scripts/plan_corpus/cross_section_check.py consumed + extended at §06.4, also consumed by §12.1)
06.5 path-scoped-committest_commit_capability_interface + test_commit_result_contract_shape + test_commit_failure_zero_halt_disposition + test_commit_failure_does_not_advance_route (tests/test_commit_capability.py)the engine routes to the commit capability with the node’s touches: scope against a mocked backend (closes against the mock, not §07’s wiring); the CommitResult dataclass field + ok/not-ok population invariants are pinned so §07 wires the real backend against a fixed contract; a commit failure routes to quarantine (NOT log_and_continue) emitting no action: halt/AskUserQuestion, and serve_next never advances to a successor while the node’s cures are uncommitted (INV-7 zero-halt + change-isolation)
06.5 soaktest_soak_convergence_monitor + test_soak_nonconvergence_autopilot_disposition (tests/test_soak.py)a true non-convergence emits the named GENUINE halt soak_nonconvergence; transient redispatch does not (feeds §12); soak_nonconvergence carries autopilot_disposition: structured_exit and routes through cure_dispatch with NO AskUserQuestion/action: halt in autopilot (zero-halt INV-7)
  • python -m scripts.plan_corpus check plans/scripts-first-restructure/section-06-*.md exit 0. exit 0
  • /tpr-review passed (final, full-section). /review-plan ran 3 /tpr-review rounds, verdict MINOR FIXES APPLIED reviewed:true (review_pipeline stage=verify-done)

References

  • Pass 1D (plan_orchestrator surface; cure_dispatch/halt_reasons absent; 7-node decomposition) + Pass 2 (§6 consolidation map + §7 seven risks).
  • §01 invariants 1, 6, 7, 8, 14, 16, 18, 20; refinement 6 (engine decomposition); decisions/02-content-as-context-unit.md (whole-file task injection + size gate + split cure); decisions/03-plan-bug-subsumption-absorption.md (subsumption = consequence-relationship + verification-gated done + un-subsume-via-quarantine); references/restructure-charter-seed.md §2 INV-20 (strict-forward-only progress).
  • Code surfaces the section depends on (consumed, not re-authored): scripts/plan_orchestrator/rules.py (HaltReason enum SSOT §06.1 re-exports/partitions); scripts/plan_corpus/exit_reasons.py (CANONICAL_EXIT_REASONS + EXIT_REASON_ROUTING parity SSOT §06.3 anchors on); scripts/commit_push/rules.py + .claude/rules/commit-push-rules.json (commit-push halt-string SSOT §06.1 COMMIT_PUSH_HALT_STRINGS derives from); scripts/plan_orchestrator/auto_cure_loop.py (LoopExitReason orchestrator halt/continuation strings §06.1 enumerates); scripts/plan_corpus/invariant_gate.py (gate_internal_error source); scripts/plan_corpus/cross_section_check.py (STRUCTURE:invariant-acceptance-hook-missing detector §06.4 consumes); scripts/plan_corpus/migrations/006_md_to_json.py:build_plan_json_from_dir (substrate parser SSOT route_walk reuses).

HISTORY

  • 2026-05-29 — §07A v7 route schema supersedes the v6 flat-node engine contract: the route schema v7 two-level plan.json (sections[] + flat work_items[], per §07A + decisions/04-sections-work-items-split.md) supersedes §06’s v6 flat-node nodes[] model; §06’s v6 engine stays complete but route_walk.serve_next is reshaped to walk sections[] then work_items[], return the current work_item, and own the work_item status lifecycle (write-on-serve + read-only peek_next) per §07A.4.