100%

Section 03 — Minimal JSON-Authoring Substrate

Bootstrap substrate; lands before §04 so converted plans are per-plan executable without the §05 cross-plan engine.

Goal

See frontmatter. Three pieces: routing-only schema + write API (03.1), the net-new id-keyed scanner (03.2), per-plan serve_next (03.3). All per-plan; no cross-plan dependency.

Intelligence Reconnaissance

  • 2026-05-28 — graph queries grounding the §03 substrate scope:
    • scripts/intel-query.sh symbol-plans serve_next --repo ori — confirms [ori:scripts/plan_corpus/graph.py:188] plan-agnostic implementation; serve_next consumes a Graph keyed by nodes; cross-plan hints currently filter via h in self.nodes (line 188-189) and silently drop non-local references.
    • scripts/intel-query.sh file-symbols scripts/plan_corpus/graph.py --repo ori — confirms Graph.from_plan_json, serve_next, relocate_past_blocker, escalate, merge_nodes are the API surface the §03.3 per-plan substrate reuses unchanged on the in-plan node set; the cross-plan hint wrapper layers on top.
    • scripts/intel-query.sh symbol-plans check_item --repo ori — confirms check_item consumes JSON line-numbers (NOT id-in-markdown scanning); grounds §03.2 net-new checkbox_scan.py introduction as a non-duplicating layer atop existing JSON-line discipline.
  • Summary (≤500 chars): §03 is a bootstrap substrate consuming the §02-emitted routing-only plan.json (INV-3) + delivering schema (§03.1), id-keyed scanner (§03.2), per-plan serve_next reuse + cross-plan hint wrapper (§03.3), todo-yah render view (§03.4); all per-plan; NO §05 cross-plan engine dependency. Schema is the SSOT for the INV-17 + INV-19 + INV-20 impossible-state invariants. The cross-plan hint wrapper closes the silent-drop gap surfaced by serve_next graph-filtering.

03.1 — plan.json routing-only schema + atomic write API

  • Author scripts/plan_corpus/schemas/v6/plan-routing.schema.json — formal version landed 2026-05-28 (bootstrap-stub title retired; migration_stamp field removed per §02.R DD-01 RESET-only policy).
  • INV-19 schema rejects branch-encoding fields on nodes[]additionalProperties: false at RoutingNode covers all listed fields; test_k_validate_raises_on_every_invariant_path negative pins cover the matrix.
  • Author the atomic plan.json write API — landed at scripts/plan_corpus/plan_json_write.py:78 mutate_routing_state (fcntl.flock-serialized read-modify-write, tempfile + os.replace, schema-validation BEFORE disk write, expected_read_base_hash CAS per state-discipline.md §4). 8/8 tests pass (scripts/plan_corpus/tests/test_plan_json_write.py).
  • INV-17 cross-field invariant — Completion subschema authored at schemas/v6/plan-routing.schema.json:63 with required {verifier, verified_at, body_hash, gates_verified}; allOf if/then at lines 56-61 makes status: done UNREPRESENTABLE without Completion.
  • INV-20 strict-forward — Completion.gates_verified at schemas/v6/plan-routing.schema.json:74 has minItems: 1; test_j_inv20_gates_verified_positive_negative_pins covers the {empty, missing, non-empty, in-progress+gates} matrix.
  • Subsection close (03.1) — all [x]; status: complete.

03.2 — id-keyed checkbox scanner (NET-NEW; fenced-block skip)

  • Author scripts/plan_corpus/checkbox_scan.py — fence-state machine tracks ``` and ~~~ opener families separately; suppresses matching inside fences.
  • Match ^\s*- \[(x| )\] \[([^\]]+)\] on non-fenced lines → CheckboxEntry{id, checked, line} (1-indexed). derive_node_status(entries) returns done (all checked) / in-progress (mixed) / not-started (empty or all unchecked).
  • This is the SOLE status-derivation mechanism (single update point, INV-10); item status lives ONLY in the content markdown checkbox.
  • INV-18 content-size lint — scripts/plan_corpus/content_size_lint.py authored; DEFAULT_CAP = 300 per routing.md §5; check_content_file() + scan_content_dir() flag over-cap content ids; cap is a content lint NEVER a plan.json field (INV-3 preserved); whole content/<id>--<slug>.md is the read contract (no fragment / section_info slice). 18 tests pass (scripts/plan_corpus/tests/test_checkbox_scan.py).
  • Subsection close (03.2) — all [x]; status: complete.

03.3 — per-plan serve_next (reuse graph.py)

  • Build a per-plan Graphscripts/plan_corpus/per_plan_route.py:build_graph_from_plan_json converts v6 routing-only plan.json nodes to graph.Node instances; graph.serve_next/relocate/escalate/merge_nodes reused unchanged on the in-plan node set.
  • Authored cross-plan hint-resolution wrapper — serve_next_with_cross_plan(graph, corpus_lookup) at scripts/plan_corpus/per_plan_route.py:78. For each candidate node’s hint_needs NOT in graph.nodes, queries corpus_lookup(node_id) -> str|None; defers the candidate when any cross-plan hint is non-done (status-lookup, NOT relocation trigger).
  • Cross-plan hint_needs semantics: satisfied (done) → ignore; unknown (None from corpus_lookup) → ignore; unsatisfied (non-done) → defer this node. Relocation never moves nodes across plans (refinement 4 preserved by construction).
  • Tests: positive pin (cross-plan hint satisfied → served); negative pin (cross-plan hint unsatisfied → deferred to next in-plan candidate); pin (all candidates blocked → None); pin (in-plan relocation still works through graph.serve_next); pin (corpus_lookup never called for in-plan hints). 13 tests pass (scripts/plan_corpus/tests/test_per_plan_route.py).
  • Subsection close (03.3) — all [x]; status: complete.

03.4 — render.py —view todo-yah (linear-walk visibility view per §00.4)

  • Author scripts/plan_corpus/render_todo_yah.py:render_todo_yah(plan_json, *, content_dir, active_node_id, drift_node_ids) — emits ASCII linear walk in lexorank order from a v6 routing-only plan.json; per-row format <marker> <plan_id>:<node_id> <slug>[ <-- YOU ARE HERE].
  • Marker semantics: [x] = status: done + completion present (INV-17 attestation gate); [>] = status: in-progress OR status: in-review; [ ] = status: not-started; [!] = drift (done-without-attestation OR explicit drift_node_ids member OR unknown status).
  • YAH annotation — active_node_id parameter accepts the currently-active node id; matching row gets <-- YOU ARE HERE appended (ASCII only; no Unicode arrows).
  • Deterministic — pure-function render; lexorank key sort is total-order with id tiebreak; no time.time() / random / session state. test_render_is_deterministic_across_repeated_calls pins byte-identity.
  • Tests: lexorank ordering pin; per-status marker pins (not-started, in-progress, in-review, done with completion, done without completion = drift); explicit drift_node_ids pin; unknown-status drift pin; YAH annotation pin (present + absent); empty plan pin; ASCII-only pin; plan_id-in-row pin. 14 tests pass (scripts/plan_corpus/tests/test_render_todo_yah.py).
  • Subsection close (03.4) — all [x]; status: complete.

03.R — Third Party Review Findings

  • [TPR-03-001-agy+claude-ds][Major] STRUCTURE:atomic-flip-violation (filed 2026-05-28 /tpr-review cap-exit): §02 frontmatter status: complete + reviewed: false violates state-discipline.md §4 atomic-flip discipline — reviewed: true is the §00.3 close-out gate that must flip before/with status: complete. Not inline-curable by /tpr-review (state-discipline.md §4: reviewed: field owned exclusively by flip_from_in_review_clean() at /review-plan close-out). Cure: when /review-plan §02 next runs Step 7+8 §02.3 close-out, the atomic flip will resolve. Surfaced here for §03 close-out completeness; §03 reviewed:true flip blocked on this until §02 is fully closed.

References

  • Pass 1B: graph.py serve_next/relocate/escalate/merge (:176/:209/:216/:230/:243) plan-agnostic; lexorank.py API.
  • Pass 1C: scanner net-new; write.py:check_item uses JSON line not id-scan; fenced-skip not implemented today.
  • §01 invariants 4 (linear walk/relocate), 5 (cyclic-impossible), 9 (single update point), 10.
  • §03A — Substrate verification gates (migrated §03.N close-out per deadlock-cure 2026-05-28 Option 1).

HISTORY

  • 2026-05-28 — Deadlock cure (Option 1: migrate cycle-causing subsection): §03.N Completion Checklist migrated to new sibling section-03A-substrate-verification.md. §03 deliverables §03.1-§03.4 are all status: complete; the prior §03.N close-out gates (pytest substrate suite, negative-import test, plan_corpus check, /tpr-review final) gated §03 close on downstream verification work, holding 9 dependent sections (§04-§12) waiting on §03. Per recommended_unblock Option 1, the gates moved to §03A so §03 flips status: complete on its own deliverables. §03A carries depends_on: ["03"] and owns the verification gates. §03.R TPR-03-001 (reviewed:true blocked on §02 fully closing) remains in §03 — that finding is about §03’s reviewed: flip ownership, not its status: flip.
  • 2026-05-29 — §07A v7 route schema supersedes the v6 substrate contract: the route schema v7 two-level plan.json (sections[] + flat work_items[], per §07A + decisions/04-sections-work-items-split.md) supersedes the v6 flat-node nodes[] model; §03’s v6 substrate stays complete but the id-keyed checkbox scanner is deprecated and the v7 work_item status write API + both v7 validators (array==sorted+unique, JSON<->md coherence) are added per §07A.3.