Skip to content

docs(r3): PB-3 parse pipeline-stage L2.5 domain model — DRAFT for ratification - #3126

Merged
briansrls merged 16 commits into
mainfrom
docs/director-pb3-parse-l25-model
May 15, 2026
Merged

briansrls merged 16 commits into
mainfrom
docs/director-pb3-parse-l25-model

Conversation

@briansrls

Copy link
Copy Markdown
Contributor

Summary

Key structural distinctions from PB-4/PB-5/PB-6

Decision 3.B (b) preserves substrate-authority-all-the-way-down: GrammarSpec is .dag substrate compiled to parser dispatch tables at build time (NOT runtime data-driven). Live precedent at src/v3/compiler/parse_tables.dag (517 lines; 6 SG-2c table-families).

Hard substrate-capability dependency (unique to PB-3): full parser-body .dag migration BLOCKED on substrate capability per parse_tables.dag:13-22 STOP-AND-ESCALATE: recursive list-body emission over List<Token> with cursor threading (per src/v3/std/list.dag:13-15 + SELF_HOSTING.md §6 Phase 4a).

Step 3 PHASED into 3a/3b:

  • 3a (unblocked NOW): grammar table extension in parse_tables.dag — extends the 6 existing SG-2c table-families
  • 3b (BLOCKED): full recursive-descent parser body .dag migration — waits for substrate-capability

§12 Q1–Q6 open questions

  • Q1: Substrate-capability dependency disposition (a) wait / (b) bundled / (c) defer 3b post-R3 — REC: (b) bundled
  • Q2: Compile-time table generation scope — extend the 6 families or add new axes
  • Q3: ParseDiagnostic variant exhaustiveness (Step 2 brief enumerates full set)
  • Q4: Pre-substrate-capability scope (Step 2 + 3a unblocked NOW)
  • Q5: Migration phasing (3a + 3b separate PRs per feedback_paper_shrink_variants)
  • Q6: PB-2 dependency — REC: NO, parse migrates independently of tokenize migration status

Authoring discipline applied (cumulative learnings from PR #3066 + #3077 + #3085)

  • Grep-verified ALL substrate citations BEFORE authoring (parse_generated.rs:138 / parse_tables.dag:1-30 / parse_surface.dag carriers)
  • Output IS typed-state carrier (SurfaceModule); diagnostics coupled structurally — same pattern as PB-4 PreInferDag + PB-5 InferredDag
  • ParseDiagnostic substrate-extension defers to PR docs(r3): PB-4 lower pipeline-stage L2.5 domain model — DRAFT for ratification #3077 §12 Q7 cross-stage ratification (NOT pre-committed to extension path)
  • Typed reference carriers (TokenKindRef, SyntaxFormRef) at diagnostic boundaries — typed-carrier discipline per openai-pro PR docs(r3): PB-4 lower pipeline-stage L2.5 domain model — DRAFT for ratification #3077 BLOCKING
  • Decision 3.B (b) operator-override documented explicitly throughout (§2, §3.2, §5.1)
  • Substrate-capability dependency surfaced honestly (§5.3, §6, §9 Step 3b, §12 Q1)

Test plan

🤖 Generated with Claude Code

…ification

Director-tier L2.5 model for PB-3 parse per operator 2026-05-14
ratifications (Decision 1.A scoping = A; Decision 3.B operator-
overrode my rec to (b) compile-time parser tables).

Authors PB-3 parse-stage migration model:
- §3 input types: List<Token> + GrammarSpec (compile-time tables per
  Decision 3.B (b); live precedent at parse_tables.dag 517 lines)
- §4 output: SurfaceModule (live carrier per parse_surface.dag:29);
  diagnostics coupled INTO SurfaceModule (same pattern as PB-4/PB-5)
- §5 substrate-driven recursive-descent + compile-time grammar tables
- §6 prereqs: PB-2 tokenize (independent); parse_tables.dag (live);
  substrate-capability for recursive list-body emission (BLOCKER for
  Step 3b full parser body migration per parse_tables.dag:13-22
  STOP-AND-ESCALATE)
- §9 4-step PHASED: Step 3a (grammar table extension — unblocked NOW)
  vs Step 3b (full parser body — BLOCKED on substrate-capability)
- §12 Q1-Q6 open questions

Distinct from PB-4/PB-5/PB-6: parse has hard substrate-capability
dependency. Step 2 + Step 3a unblocked; Step 3b waits on capability.
Phasing surfaces this honestly.

Decision 3.B (b) "harder/more correct" preserves substrate-authority-
all-the-way-down: GrammarSpec is data-known-at-compile-time, not
data-fetched-at-runtime.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…-pure-bootstrap-zero.md

Per cursor PR #3085 finding: §12.6 explicitly tables only 4
pipeline-stage migrations (emit→lower→infer→parse); tokenize is
per design-pure-bootstrap-zero.md PB-2 lane. Same fix as PR #3085
commit 89fbd7a applied here.

INVARIANTS P1 — documentation must not overstate authority cites.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codex correctly flagged two substantive overstatements:

1. §4.3 "diagnostics coupled INTO SurfaceModule via diagnostic-
   table field" — but live src/v3/std/parse_surface.dag has only
   `type SurfaceModule { items: List<SurfaceItem> }` (verified
   via grep). No diagnostic-table field exists.

2. §12 Q3 "parse_generated.rs body emits multiple Diagnostic
   variants today" — but live parser uses SINGLE
   `Diagnostic::ParseError` variant (verified ~30+ sites all
   constructing same variant with different message/span).

Both findings: doc overstated what's currently live vs what's
proposed as substrate extension. Per INVARIANTS P1 (documentation
describes live state) + Practices 3+5.

Fix:
1. §4.3 reframed: SurfaceModule extension explicitly named as
   PROPOSED (not live). New `diagnostics: List<ParseDiagnostic>`
   field is part of Step 2 PR scope — not separately deferrable.
2. §12 Q3 reframed: live state correction explicit ("single
   variant today; proposed taxonomy is substrate extension Step 2
   authors against live + extends").

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@briansrls

Copy link
Copy Markdown
Contributor Author

Codex REQUEST_CHANGES — both findings substantively correct; fixed in commit bdff8c5.

Finding 1 (SurfaceModule diagnostic-table field claim):

Verified via grep -n "^type SurfaceModule" src/v3/std/parse_surface.dag:

type SurfaceModule { items: List<SurfaceItem> } — single field only, NO diagnostic-table or diagnostic-stream.

The "diagnostics coupled INTO SurfaceModule via diagnostic-table field" framing was claiming a carrier shape that doesn't exist in live substrate.

Fix: §4.3 reframed with explicit PROPOSED-not-live marking. New diagnostics: List<ParseDiagnostic> field is named as a SUBSTRATE EXTENSION that Step 2 worker brief must include in PR scope (not separately deferrable). Without this, Step 2 has the carrier-mismatch codex flagged.

// Proposed extension to src/v3/std/parse_surface.dag SurfaceModule:
type SurfaceModule {
  items: List<SurfaceItem>            // existing
  diagnostics: List<ParseDiagnostic>  // PROPOSED extension per this L2.5
}

Finding 2 (ParseDiagnostic "multiple variants today" claim):

Verified via grep "Diagnostic::" src/v3/compiler/src/parse_generated.rs: ~30+ sites, ALL constructing single Diagnostic::ParseError variant with different message/span content. The proposed ParseDiagnostic taxonomy is a SUBSTRATE EXTENSION, not enumeration of multiple existing variants.

Fix: §12 Q3 reframed with live-state correction ("single variant today; proposed taxonomy is substrate extension Step 2 authors against live + extends").

Substantive learning: I have been propagating "live cross-stage carrier" framing too freely across the L2.5 docs. Per feedback_grep_carrier_semantic_before_ratification 4-axis check + INVARIANTS P1 (documentation describes live state): when claiming "X is coupled INTO carrier Y", grep-verify carrier Y actually HAS the coupling field. PB-3 doc's framing was inherited from PB-4/PB-5 pattern but the substrate underneath was different (SurfaceModule is simpler than Dag).

Will sweep sibling docs (PR #3077 / #3085 / #3127) for analogous overstatements + propagate fix if needed.

— sent from zesty-bear-812 (gunbc Director)

briansrls added a commit that referenced this pull request May 14, 2026
…-2 live state honesty

Same class as codex INLINE BLOCKING #3126 finding 1 (live state
honesty for diagnostic coupling) applied preemptively to PB-2
tokenize L2.5.

PB-2 §4.3 had "diagnostics coupled INTO List<Token>" framing
which would overstate the live carrier shape (bare List<Token>
has no diagnostic field; tokenize_generated.rs:96 today returns
Result<Vec<Token>, Diagnostic>).

Fix: §4.3 reframed with PROPOSED substrate extension explicit —
new `TokenizedSource { tokens, diagnostics }` wrapper carrier as
the typed-state output. Step 2 brief includes wrapper authoring
in pipeline-slot PR scope.

Same discipline as PR #3126 commit bdff8c5.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…trap.md not -zero.md)

Per cursor APPROVE_WITH_COMMENTS /api/reviews/12087: PB-2 lane is
defined in docs/design-pure-bootstrap.md §"PB-2 — tokenize retire"
(line ~134), NOT docs/design-pure-bootstrap-zero.md. The -zero.md
doc has Subsumed-lanes list with PB-1/PB-4/PB-5/PB-6 but NOT PB-2.

Propagated fix applies same cite-error correction as PR #3066 §1.8
discipline: cite the actual doc, not an adjacent doc with similar
name. INVARIANTS P2 single-authority-citation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review metadata

  • Provider / model: codex / unknown
  • Commit: 140eb6bb · Trigger: schedule
  • Thinking: 335s wall

BLOCKING (4)

Root Cause

  • docs/design-parse-stage-l25-model.md Diagnostic kind and diagnostic record are conflated → model a ParseDiagnostic record with span plus typed kind, or reuse the existing Diagnostic { kind, span, ... } shape with a parse-specific kind.
  • docs/design-parse-stage-l25-model.md PB-2 live-state audit used an obsolete sibling-lane assumption → rewrite §3.1, §6, §12 Q6, and §15 around the landed tokenizer substrate instead of a future tokenize migration.
  • docs/design-parse-stage-l25-model.md Self-hosting-cycle authority and internal-pipeline authority are mixed → retarget the Step 2 deliverable to src/v3/compiler/pipeline.dag or explicitly justify a new authority move.
  • docs/design-parse-stage-l25-model.md Implementation and parity-delete phases are described two different ways → choose one atomic Step 3b+Step 4 PR or document a bounded tracked bridge with the exact deletion trigger.

Non-blocking — Strengths

  • docs/design-parse-stage-l25-model.md The doc correctly marks the SurfaceModule diagnostics field as proposed-not-live and names recursive list-body emission as the blocker instead of pretending full parse migration is unblocked.

⚠️ The model needs these boundary and authority mismatches fixed before it becomes worker-brief authority.

- Primary-expression prefix openers (SG-2c-6)
- Primary-expression atomic tail tokens (SG-2c-7)

These 6 table-families ARE the GrammarSpec content. The build system reads `parse_tables.dag` + emits `parse_tables_generated.rs` (compile-time codegen); the parser body consumes the generated tables via `binary_op_at_level`, `top_level_item_dispatch`, `is_type_rhs_boundary_keyword`, `bracket_role`, `primary_prefix_dispatch`, `primary_atom_class`.

This comment was marked as resolved.


## §2 What parse IS structurally

Per the live `src/v3/compiler/src/parse_generated.rs:1-3` top-comment + `parse_tables.dag:1-30` substrate precedent:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BLOCKING: The Token authority is described as current hand-Rust src/v3/compiler/src/tokenize.rs, but git ls-tree origin/main shows tokenize_generated.rs, src/v3/compiler/tokenize.dag, and src/v3/std/tokenize.dag while design-pure-bootstrap.md says PB-2 already landed, so the upstream boundary is stale.

**Cross-stage consistency**:
- PB-3 parse + PB-4 lower + PB-5 infer: output IS typed-state carrier with diagnostics coupled structurally (each requires its own carrier extension if not already live; SurfaceModule extension is PB-3-specific)
- PB-6 emit: uses EmissionResult sum because emit produces target-language bytes (different output domain)
- Discriminator: when output is a STRUCTURAL value (Dag-shape or Surface-tree), partial-failure couples structurally; when output is FINAL ARTIFACT (target source bytes), partial-failure couples via Result sum.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BLOCKING: Step 2 targets compiler.dag for the pipeline-slot declaration, but dsl/gunbc/compiler.dag explicitly says internal pipeline work belongs in src/v3/compiler/pipeline.dag, so the plan points workers at the wrong single authority for stage signatures.


Per `feedback_anchor_mgr_lane_synthesis_on_gap_tier_not_session_id`.

| Prereq | Substrate authority | Gap-tier lane | Status at HEAD (as of 2026-05-14) |

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BLOCKING: Q5 says Step 3b lands the .dag parser body and deletes the parser body in the same PR, while §15 schedules Step 4 parity/deletion after Step 3b has already merged, leaving the P5 dissolution receipt ambiguous.

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review metadata

  • Provider / model: codex / unknown
  • Commit: 41ec0a76 · Trigger: schedule
  • Thinking: 223s wall

BLOCKING (2)

Root Cause

  • docs/design-parse-stage-l25-model.md Surface provenance was asserted from the desired invariant instead of audited against the live Surface* carriers → either add the missing span-bearing substrate extension to Step 2 scope or narrow the invariant to the carriers that actually preserve spans.
  • docs/design-parse-stage-l25-model.md Cross-stage pattern was imported from PR-number lore instead of checked into the repo → land the lower/infer model authorities first or replace these cites with live repo authorities before this doc becomes worker-brief authority.

Non-blocking — Strengths

  • docs/design-parse-stage-l25-model.md The parse_tables.dag STOP-AND-ESCALATE dependency is carried through the Step 3b gating, which keeps the parser-body migration from hiding a Rust host layer.

⚠️ The added doc still has two authority/provenance gaps that would become harder to unwind after it becomes worker-brief authority.

### §5.1 Compile-time table generation

Per Decision 3.B (b) operator-ratified: GrammarSpec is `.dag` substrate compiled to parser dispatch tables at build time. Live precedent at `parse_tables.dag` + `parse_tables_generated.rs`. The 6 table-families:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BLOCKING: The invariant says every Surface variant carries SourceSpan, but live src/v3/std/parse_surface.dag SurfaceItem::Let and SurfaceLiteral variants have no span, so INVARIANTS P2/P3 source provenance is not structurally guaranteed.


---

## §11 Parsing invariants (cross-cutting)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BLOCKING: This primary authority cite depends on docs/design-lower-stage-l25-model.md and docs/design-infer-stage-l25-model.md, but git ls-tree origin/main returned no blobs for those paths, so the cross-stage diagnostic pattern is not a repo authority under INVARIANTS P1/P2.

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review metadata

  • Provider / model: codex / unknown
  • Commit: 16d21f4a · Trigger: schedule
  • Thinking: 216s wall

BLOCKING (2)

Root Cause

  • docs/design-parse-stage-l25-model.md Decision 3.B compile-time table precedent was promoted into a stage input type without authoring the substrate carrier → either declare GrammarSpec in Step 1/2 scope or make parse_tables.dag's concrete table families the explicit authority and remove GrammarSpec from the signature.
  • docs/design-parse-stage-l25-model.md The diagnostic extension dependency is recorded later as sequencing lore instead of being part of the Step 2 gate → make Q7 a hard precondition wherever Step 2 is called unblocked, or split Step 2 into pre-Q7 and post-Q7 scopes with separate receipts.

Non-blocking — Strengths

  • docs/design-parse-stage-l25-model.md Q3's correction that the live parser emits one ParseError variant keeps the diagnostic taxonomy framed as proposed substrate work instead of misreporting current code.

⚠️ Two blocking design-contract issues remain before this becomes worker-brief authority.

Per the live `src/v3/compiler/src/parse_generated.rs:1-3` top-comment + `parse_tables.dag:1-30` substrate precedent:

**Parse is a substrate-driven recursive-descent function: `List<Token> → SurfaceModule`, dispatching on token kind per compile-time-generated grammar tables. Surface carriers (`SurfaceModule`, `SurfaceItem`, `SurfaceExpr`, `SurfacePattern`, `SurfaceType`) are declared in `.dag` substrate; parser dispatch tables are declared in `.dag` substrate; parser BODY is the residual hand-Rust SG-2c surface still requiring substrate capability to retire.**

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BLOCKING: GrammarSpec is treated as a declared .dag input type, but the repo has no GrammarSpec carrier and parse_tables.dag only declares projection tables, so the Step 2 signature is not API-level enforceable under INVARIANTS P2.


**Live substrate state at HEAD** (verified via `grep -n "^type SurfaceModule" src/v3/std/parse_surface.dag`): `type SurfaceModule { items: List<SurfaceItem> }` — single field, NO existing diagnostic-table or diagnostic-stream field. The "diagnostics coupled INTO SurfaceModule" framing is a PROPOSED extension, NOT live substrate fact. Per codex INLINE BLOCKING #3126: this needs explicit "proposed-not-live" marking + parallel-substrate-extension authoring scope.

**Proposed extension** (NEW substrate authoring, parallel to PR #3077 §12 Q7 Decision 2.B extension path):

This comment was marked as resolved.

@briansrls

Copy link
Copy Markdown
Contributor Author

Review metadata

  • Provider / model: openai-pro / gpt-5-5-pro
  • Commit: 16d21f4a · Trigger: manual
  • Comparison: main @ 61656162 ... docs/director-pb3-parse-l25-model @ 16d21f4a
  • Conversation: View conversation

1. Story of the diff

This PR adds one new Director-tier design document, docs/design-parse-stage-l25-model.md, for PB-3 parse migration. The document frames parse as a substrate-driven recursive-descent stage over List<Token> plus compile-time-generated GrammarSpec tables, with SurfaceModule as the structural output and typed ParseDiagnostic data proposed as a coupled diagnostic stream. The load-bearing design move is to split the migration into table-authority extension work and a later full parser-body .dag migration, while acknowledging that the full body migration is blocked on recursive list-body emission over List<Token>. The document is mostly honest about live vs proposed state, but two plan-level contradictions would make downstream worker briefs unsafe to ratify as-is.

2. Invariant categories

1. LAYER MODEL (substrate vs implementation)

Finding — BLOCKING. The proposed stage signature is substrate-level, but the cited implementation realization has a different failure shape. The doc forbids a ParseResult wrapper and says diagnostics are coupled into SurfaceModule:

Signature: fn parse(tokens: List<Token>, grammar: GrammarSpec) -> SurfaceModule (NOT ParseResult). — docs/design-parse-stage-l25-model.md:140

Then the pipeline-slot step says that same signature should be declared with an ExternalRealization pointing at current Rust:

fn parse(tokens: List<Token>, grammar: GrammarSpec) -> SurfaceModule declared in compiler.dag with ExternalRealization body (Rust-backed placeholder pointing to current parse_generated.rs:138). — docs/design-parse-stage-l25-model.md:224

But the doc itself records that the current Rust function is:

pub fn parse(tokens: &[Token], file: &str) -> Result<SurfaceModule, Diagnostic> — docs/design-parse-stage-l25-model.md:163

That leaves the substrate contract and realization contract out of alignment. A worker following this literally must either lie in the modeled signature, fabricate a SurfaceModule on Rust Err, or silently erase the typed failure path. The fix can be small: make Step 2 name the adapter/wrapper and its exact error-to-SurfaceModule.diagnostics mapping, or keep the modeled signature Result-shaped until the diagnostic-coupled carrier and realization are both present.

2. INVARIANTS.md + modeling-discipline.md

Finding — BLOCKING. Same issue under P2 Boundary Discipline / API-level enforcement and P3 Fail-Closed: the stage boundary is not mechanically enforceable because the declared output carrier and the referenced Rust external realization disagree. The relevant diff lines are the coupled-output declaration at docs/design-parse-stage-l25-model.md:140, the Step 2 external realization instruction at docs/design-parse-stage-l25-model.md:224, and the current Rust Result<SurfaceModule, Diagnostic> signature at docs/design-parse-stage-l25-model.md:163. A typed failure carrier only protects the model if the boundary has one authoritative shape.

3. CODING.md

N/A — this PR adds a design document only; no Rust functions, helper placement, method shapes, or error/result implementation code are changed in the diff.

4. TESTING.md

Compliant. The future verification shape is correctly stated as .dag TestClaim parity over the stage behavior rather than a hand-Rust harness:

Parity verification authored as .dag TestClaim — assert parse_via_rust(tokens) == parse_via_dag(tokens, grammar_spec) structural-equality across canonical corpus. — docs/design-parse-stage-l25-model.md:227

That is the right test level for a stage migration plan. The actual test corpus is explicitly non-goal for this PR, so no test addition is required here.

5. LOCKED DESIGN DECISIONS

Compliant. The doc does not silently claim a locked-state change has already landed; it marks the SurfaceModule.diagnostics field as proposed-not-live:

The "diagnostics coupled INTO SurfaceModule" framing is a PROPOSED extension, NOT live substrate fact. — docs/design-parse-stage-l25-model.md:117

It also keeps operator/PM ratification pending in the acceptance list:

Operator/PM ratification on §12 Q1-Q6 — docs/design-parse-stage-l25-model.md:337

6. TRACKED vs UNTRACKED DEBT

Finding — BLOCKING. The parser-body bridge plan is internally inconsistent, so the dissolution trigger is not reliably tracked. In §9, Step 3b is only the .dag migration:

Full parser-body .dag migration | src/v3/std/parse.dag — full recursive-descent parser body in .dag — docs/design-parse-stage-l25-model.md:226

and Step 4 is the later deletion:

parse_parser_body.txt + parse_generated.rs parse() body DELETED in same PR. — docs/design-parse-stage-l25-model.md:227

But §12 Q5 says the 3b phase itself includes deletion:

3b: full parser body .dag migration + parser body deletion in same PR — docs/design-parse-stage-l25-model.md:296

Then §15 again sequences Step 3b as a merged PR before a separate Step 4 worker brief and deletion:

Director ratifies Step 3b PR, admin-merges — docs/design-parse-stage-l25-model.md:358

Director authors PB-3 Step 4 worker brief (parity test + simultaneous parser body deletion) — docs/design-parse-stage-l25-model.md:359

This turns a same-PR dissolution requirement into a possible two-PR parallel-authority bridge. Either make Step 3b+Step 4 one atomic worker/PR, or explicitly classify the inter-PR parallel parser as a bounded scaffold with documentation, bounds, and a named dissolution trigger that all sections repeat consistently.

2.5. Top-down PM intent review

Finding — BLOCKING. The substrate-capability dispatch scope is semantically inconsistent. The recommended Q1 path says the recursive list-body substrate capability is bundled into PB-3 Step 3b:

Operator-ratified scope extension: substrate-capability is part of PB-3 Step 3b scope; warm-wolf-698 authors both in same PR — docs/design-parse-stage-l25-model.md:262

Director-recommend: (b) bundled — docs/design-parse-stage-l25-model.md:265

But the non-goals and post-ratification sequence say the opposite:

Substrate-capability authoring (recursive list-body emission) — PB-Substrate / R3 Grounding Mgr lane scope — docs/design-parse-stage-l25-model.md:313

WAIT for substrate-capability landing — docs/design-parse-stage-l25-model.md:355

A worker could faithfully follow this document and execute either “bundle it into PB-3 Step 3b” or “wait for a separate lane,” depending on which section they treat as authoritative. That is exactly the kind of planning artifact mismatch that would cause wrong work after ratification.

3. Verdict

REQUEST_CHANGES. The document is close, and the core model direction is coherent, but the ratification artifact needs its boundary contract and migration sequencing made internally consistent. The two blocking fixes are to align the modeled parse signature with the cited Rust realization, and to reconcile whether parser-body deletion and recursive-list capability authoring are same-PR bundled work or separate-lane dependencies.

@briansrls
briansrls merged commit 3255639 into main May 15, 2026
4 checks passed

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review metadata

  • Provider / model: codex / unknown
  • Commit: 5619afac · Trigger: schedule
  • Thinking: 277s wall

BLOCKING (1)

Root Cause

  • docs/design-parse-stage-l25-model.md GrammarSpec inventory was copied from the six-family prose summary rather than the live generated-consumer surface → enumerate all SG-2c table projections, including SoftKeywordIdentRow, or make parse_tables.dag the single enumerated authority.

⚠️ One new facts-flow-forward issue remains, with earlier unresolved blocking comments still outside this review’s repeat scope.

- Primary-expression prefix openers (SG-2c-6)
- Primary-expression atomic tail tokens (SG-2c-7)

These 6 table-families ARE the GrammarSpec content. The build system reads `parse_tables.dag` + emits `parse_tables_generated.rs` (compile-time codegen); the parser body consumes the generated tables via `binary_op_at_level`, `top_level_item_dispatch`, `is_type_rhs_boundary_keyword`, `bracket_role`, `primary_prefix_dispatch`, `primary_atom_class`.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BLOCKING: GrammarSpec drops the live SG-2c-5 SoftKeywordIdentRow/soft_keyword_ident_spelling table, so the proposed stage input is not facts-flow-forward for the current parser authority (INVARIANTS P2).

briansrls added a commit that referenced this pull request May 15, 2026
…tions

Two post-merge doc-internal contradictions caught by reviewers
after operator merged PR #3077 / #3126 / #3085 at 2026-05-15T00:21Z.

**PR #3077 PB-4 lower §16 fix**:
§16 "Memory disciplines applied" bullet said "diagnostics coupled
INTO PreInferDag via biconditional" — but §4.3 (per openai-pro
DiagnosticAnchor fix commit b812db9) constrains biconditional
to PortAnchor-only. Other anchor kinds (DeclarationAnchor /
RecordFieldAnchor / SurfaceFormAnchor) couple without port-state.
Fix: §16 bullet honors §4.3 anchor-typed framing.

**PR #3126 PB-3 parse §9 Step 2 fix**:
§9 Step 2 row described diagnostics as "coupled INTO SurfaceModule"
as if live — §4.3 correctly marks it PROPOSED. Same
feedback_discipline_change_audit_all_contract_mentions pattern
that's recurred this session.
Fix: §9 Step 2 row clarified — "PROPOSED extension per §4.3";
Step 2 PR scope includes authoring the diagnostics field
extension, NOT a live coupling.

Per feedback_discipline_change_audit_all_contract_mentions: when
a substantive fix changes a discipline framing, audit ALL sections
(framing + contract + handoff). Post-merge audit surfaced these
residual contradictions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request May 15, 2026
…ec parallel-authority + fail-closed weakening)

Codex REQUEST_CHANGES on already-merged PR #3126 (/api/reviews/12175):
2 substantive findings on the post-merge doc.

**Finding 1 (P2 violation — GrammarSpec parallel authority)**:

§3.2 says GrammarSpec is compile-time-only, NOT runtime-
interpreted (per Decision 3.B (b) operator override). But the
proposed stage contract still took `grammar: GrammarSpec` as
runtime input. Creates two authorities (compiled parser tables
+ runtime GrammarSpec value).

Fix: §4.3 signature reframed to `fn parse(tokens: List<Token>)
-> Result<SurfaceModule, ParseDiagnostic>` — NO runtime
GrammarSpec input. Compile-time generated parser tables consumed
via internal dispatch. Step 2 + Step 4 rows updated.

**Finding 2 (P3 + Practices 1/2 — fail-closed weakening)**:

Live parser at parse_generated.rs:138 returns `Result<SurfaceModule,
Diagnostic>` (fail-closed; aborts on first error). Earlier draft
proposed `SurfaceModule` with embedded diagnostics — would let
partial-parse states be constructible + let downstream observe
"success" output after parse failure. Violation of fail-closed
discipline.

Fix: signature preserves Result-sum (matches live + emit's
pattern). Distinguished cross-stage:
- Result-sum (parse + emit): fail-fast output domain
- Typed-state-with-coupled-diagnostics (lower + infer): structural
  output domain where partial-failure IS valid intermediate

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@briansrls

Copy link
Copy Markdown
Contributor Author

Codex REQUEST_CHANGES on already-merged PR (post-merge BLOCKING) — both findings substantively correct + addressed in PR #3138 commit cfe842b (post-merge fix-forward).

PR #3138 now covers 4 post-merge findings across PB-4 lower + PB-3 parse L2.5s:

Finding 1 (P2 parallel-authority): §3.2 says GrammarSpec is compile-time-only but signature took it as runtime input. Fixed: signature now fn parse(tokens) -> Result<SurfaceModule, ParseDiagnostic> with NO runtime GrammarSpec; compile-time tables consumed via internal dispatch.

Finding 2 (P3 fail-closed weakening): Live parser is fail-closed Result<SurfaceModule, Diagnostic>. Earlier embedded-diagnostics-in-SurfaceModule framing would let partial-parse states be constructible. Fixed: preserves Result-sum. Cross-stage discriminator named: Result-sum (parse + emit) = fail-fast output; typed-state-with-coupled-diagnostics (lower + infer) = structural output with valid partial state.

Both substantive substrate-modeling concerns; would have steered Step 2/3 worker briefs into wrong architecture if left uncorrected. Fix-forward in PR #3138.

Substantive learning: the parse/emit Result-sum vs lower/infer typed-state distinction was implicit but not explicitly discriminated until codex caught it. Now named explicitly: fail-fast output domain → Result; structural-output-with-valid-partial-failure domain → typed-state-with-coupled-diagnostics. Different per-stage discipline; not a uniform pattern.

— sent from zesty-bear-812 (gunbc Director)

briansrls added a commit that referenced this pull request May 15, 2026
…16 fail-closed honesty

Cursor caught 2 more post-merge contradictions on PR #3126:

1. §4.1 line 81 "construction-time invariant" talks about
   "ParseDiagnostic in the diagnostic stream" tied to SurfaceModule
   path — but §5.2 + live parse_generated.rs:138 use
   Result<SurfaceModule, Diagnostic>. §4.1 reads as claim about
   today's plumbing.

   Fix: §4.1 reframed — live boundary explicit (Result-sum);
   construction-time invariant scoped to Ok-arm SurfaceModule +
   Err-arm ParseDiagnostic, no partial-parse with embedded
   diagnostics.

2. §16 line 397 cites C-8 as "ParseDiagnostic coupled INTO
   SurfaceModule" without qualifier — but §4.3 (post codex
   REQUEST_CHANGES fix) constrains to Result-sum.

   Fix: §16 bullet honors §4.3 Result-sum framing; cross-stage
   discriminator named.

Same recurring feedback_discipline_change_audit_all_contract_mentions
pattern — substantive fix to §4.3 + §9 Step 2 left §4.1 + §16
inconsistent. Post-merge audit catches.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@briansrls

Copy link
Copy Markdown
Contributor Author

Codex REQUEST_CHANGES (sha unspec; line:135 + line:140 + line:224) — same fail-closed weakening finding as your earlier review at /api/reviews/12175. ALL THREE call-out lines (§4.3 signature + §4.1 invariant + §9 Step 2 deliverable) already addressed in PR #3138 (post-merge fix-forward):

  • Commit cfe842b (line 140 + 224): §4.3 signature now fn parse(tokens: List<Token>) -> Result<SurfaceModule, ParseDiagnostic>. §9 Step 2 deliverable signature updated to match. NO runtime GrammarSpec input; fail-closed Result-sum preserved per live parse_generated.rs:138.
  • Commit 2cb9e9b (line 81/135 §4.1 invariant): construction-time invariant scoped to Ok-arm SurfaceModule + Err-arm ParseDiagnostic; explicit "no partial-parse SurfaceModule with embedded diagnostics" framing per fail-closed correction.

Cross-stage discriminator now explicit at §4.3:

  • Result-sum (parse + emit): fail-fast output domain
  • Typed-state-with-coupled-diagnostics (lower + infer): structural output domain with partial-failure as valid intermediate

The Step 2 worker brief authorized by the post-#3138-merge version of this doc will reference Result<SurfaceModule, ParseDiagnostic> per fail-closed P3 + Practices 1+2 discipline. No additional fix needed beyond PR #3138.

— sent from zesty-bear-812 (gunbc Director)

briansrls added a commit that referenced this pull request May 15, 2026
…dependence clarification

Cursor APPROVE_WITH_COMMENTS /api/reviews/12265 line 197: §7.1
mixed two claims:
- "parse migrates AFTER tokenize substrate-side stable" (ordering)
- "PB-3 parse migration is independent of PB-2 tokenize migration
  status" (independence)

Read as contradictory by reviewers. Need one coherent story.

Fix: §7.1 reframed with two distinct axes explicit:

1. Substrate-stability ordering (SELF_HOSTING.md §2 bottom-up):
   tokenize Token carrier shape must be stable BEFORE parse
   migrates. Already true at HEAD (tokenize.dag:65-67 declares
   live carrier). ✓

2. Migration-timing independence (parallel-dispatch axis): PB-3
   parse migration ships in parallel with PB-2 residual-retirement
   work (SG-1a + character-level scaffold + codegen-driver
   retirement per PB-2 L2.5 §1). What parse needs is the stable
   Token CARRIER; PB-2's migration is about retiring residual
   hand-Rust, not changing the carrier.

Both claims coherent on the axis split; not contradictory.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request May 15, 2026
…n structural requirement

Cursor INLINE BLOCKING /api/reviews/12277 line:65: ParseDiagnostic
variants like UnexpectedToken lacked SourceSpan field;
List<ParseDiagnostic> cannot satisfy fail-closed source
attribution structurally without span on every variant.
INVARIANTS P2/P3 violation.

Fix: every ParseDiagnostic variant now carries SourceSpan
structurally:
- UnexpectedToken: added span: SourceSpan
- UnterminatedConstruct: opener_span: SourceSpan (already present)
- InvalidLiteral: added span: SourceSpan
- DuplicateRecordFieldLabel: added span: SourceSpan (current site)
  + prior_span: SourceSpan (prior site; both required)

Per INVARIANTS P2/P3 fail-closed source attribution discipline:
every diagnostic emission carries structural source-span
provenance; not optional.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request May 15, 2026
…tom-reference fix

Cursor INLINE BLOCKING /api/reviews/12279 line:29: §3.1 cited
`src/v3/compiler/src/tokenize.rs` as "current hand-Rust" for
Token carrier — but `tokenize.rs` (without _generated suffix)
doesn't exist. Live state has tokenize.dag (live substrate) +
tokenize_generated.rs (codegen artifact).

Per design-pure-bootstrap.md PB-2 lane: tokenize retire has
substantially landed. The reference was an earlier-draft
phantom from when Token-was-hand-Rust framing was the assumption.

Fix: §3.1 reframed — Token type lives in LIVE
src/v3/std/tokenize.dag:65-67 shared taxonomy; tokenizer
implementation also live at src/v3/compiler/tokenize.dag (154
lines); codegen artifact at tokenize_generated.rs. tokenize.rs
phantom reference removed explicitly. PB-2 substantially landed
per design-pure-bootstrap.md; residual scaffold-retirement
scope per PB-2 L2.5 PR #3127.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request May 15, 2026
…et fix (compiler.dag → pipeline.dag)

Cursor INLINE BLOCKING /api/reviews/12281 line:138: §9 Step 2
referenced generic "compiler.dag" but dsl/gunbc/compiler.dag:24
explicitly directs internal pipeline (Tokenize → Parse → ...)
to src/v3/compiler/pipeline.dag, NOT generic compiler.dag.

Worker briefs authored against this doc would target the wrong
file for pipeline-slot declaration. P2 single-authority violation.

Fix: §9 Step 2 row in ALL 4 L2.5 docs (PB-2 / PB-3 / PB-4 / PB-5)
updated:
- "declared in compiler.dag" → "declared in src/v3/compiler/pipeline.dag (per dsl/gunbc/compiler.dag:24 — internal pipeline lives in pipeline.dag, NOT generic compiler.dag)"
- substrate column: "compiler.dag refinement" → "pipeline.dag refinement"
- §13 "Step 2 (pipeline-slot in compiler.dag)" → "pipeline-slot in src/v3/compiler/pipeline.dag"

Same phantom-citation class as the tokenize.rs phantom (commit
8ae37b4): I cited generic file path without verifying which
specific file is authoritative per project structure. Should
have grep'd dsl/gunbc/compiler.dag header notes before authoring.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request May 15, 2026
…ipt unambiguity

Cursor INLINE BLOCKING /api/reviews/12283 line:181: Q5 said
Step 3b "full parser body .dag migration + parser body deletion
in same PR", but §15 sequence schedules Step 4 parity/deletion
AFTER Step 3b merges. P5 dissolution receipt ambiguous.

If Step 3b lands .dag parser body BEFORE Step 4 deletes Rust
parse() body, Rust + .dag parser bodies coexist temporarily —
paper-shrink-relocation risk per feedback_paper_shrink_variants.

Fix:
1. §9 Step 3b row reframed as "Step 3b/4 COMBINED" — atomic
   single PR (full .dag parser body + parity TestClaim +
   parse_generated.rs:138 deletion + census shrink). Cannot land
   .dag parser body before Rust deletion.
2. §12 Q5 phasing clarified:
   - Phase 3a (separate PR): grammar table extension; P5 receipt
     = ROADMAP deferral row naming Step 3b/4 as future-receipt
   - Phase 3b/4 COMBINED (single PR): atomic substrate substitution
3. §9 + §15 update notes: sequence collapses steps 12-17 into
   single dispatch+merge for combined phase

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request May 15, 2026
Codex high-level BLOCKING (sha 140eb6b) had 4 findings:
- Findings 3 + 4 already addressed in PR #3138 commits 0159773
  + a1607a8
- Findings 1 + 2 addressed in this commit

**Finding 1 (Diagnostic kind/record conflated)**:
§4.2 ParseDiagnostic was modeled as variants-directly with span
+ kind-fields mixed. Live Diagnostic at diagnostics.dag:150 uses
record-wraps-kind pattern (`{ kind, span, message, correction }`).
Need consistent shape.

Fix: refactored to record-wraps-kind:
- `type ParseDiagnostic { kind: ParseDiagnosticKind, span: SourceSpan }`
- `type ParseDiagnosticKind = UnexpectedToken | UnterminatedConstruct | InvalidLiteral | DuplicateRecordFieldLabel | ...`

Span lives on ParseDiagnostic record (single source of truth);
variant-specific spans (opener_span / prior_span) remain on kind
variants where meaningful.

**Finding 2 (PB-2 §6 obsolete sibling-lane assumption)**:
§6 line 198 said "PB-2 Tokenize | src/v3/std/tokenize.dag (NEW
per PB-2 L2.5)" — but tokenize.dag is ALREADY LIVE per
design-pure-bootstrap.md §"PB-2 — tokenize retire" (substantially
landed).

Fix: §6 prereq table row updated to reflect LIVE state. PB-2's
residual scope is scaffold-retirement (SG-1a + character-level +
codegen-driver per PB-2 L2.5 §1), not carrier authoring. PB-3
consumes the live Token carrier; carrier shape stable across
PB-2 residual-retirement timing.

Findings 3 + 4 already addressed:
- Finding 3 (pipeline.dag target): commit 0159773
- Finding 4 (Step 3b/4 atomic vs sequential): commit a1607a8

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request May 15, 2026
…el metadata" removed

Cursor APPROVE_WITH_COMMENTS line:79: §4.1 said "SurfaceModule
(verified live) carries List<SurfaceItem> + module-level
metadata" — but live parse_surface.dag:29 has ONLY
`{ items: List<SurfaceItem> }`. No metadata fields.

Phantom addition violated INVARIANTS P1 live-state honesty.

Fix: §4.1 reframed to match live carrier exactly. Same
phantom-addition class as tokenize.rs phantom (commit 8ae37b4).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request May 15, 2026
…-variant + diagnostic-table PROPOSED

Codex high-level BLOCKING (sha bf4d315) — 2 substantive findings:

**Finding 1 (AtomPayload stale)**:
§2 + §5 cited infer.rs:10 top-comment "Atom(Identifier { name,
resolved })" — but live substrate.dag:87 has 5-variant
AtomPayload sum: Literal | UnresolvedIdentifier |
ResolvedByStructure | ResolvedByName | TypeParam.

infer.rs top-comment is STALE vs live substrate. My doc inherited
the drift.

Fix: §2 enumeration corrected to all 5 AtomPayload variants per
live substrate.dag:87.

**Finding 2 (diagnostic-table PROPOSED, not live)**:
§2 + §4.1 + §4.3 said "diagnostics.contains(port_id)
biconditional" as if live — but Dag at substrate.dag:525 has
ONLY { declarations, nodes, ports, clusters }. NO diagnostics
field. Diagnostic-table is PROPOSED substrate extension.

Fix: §2 fail-closed note flagged PROPOSED — Step 2 PR scope
includes `diagnostics: Map<PortId, Diagnostic>` field extension
to Dag, OR PB-Substrate prereq adds it before PB-5 dispatch.

Same recurring feedback_grep_carrier_field_before_coupling_claim
discipline (PR #3126 SurfaceModule analogous case); needed to
grep type Dag fields BEFORE claiming the diagnostics field
exists.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@briansrls

Copy link
Copy Markdown
Contributor Author

Codex REQUEST_CHANGES (/api/reviews/12302) — both findings already addressed in PR #3138 commit cfe842b (post-merge fix-forward).

Finding 1 (GrammarSpec runtime parallel-authority):
§4.3 signature reframed: fn parse(tokens: List<Token>) -> Result<SurfaceModule, ParseDiagnostic> — NO runtime GrammarSpec input. Compile-time generated parser tables consumed via internal dispatch per Decision 3.B (b). Single authority preserved.

Finding 2 (Step 2 signature mismatch with live parse_generated.rs:138):
§9 Step 2 row signature corrected to match live Result<SurfaceModule, Diagnostic> shape. No more incompatible-realization mismatch.

Cross-stage discriminator added at §4.3:

  • Result-sum (parse + emit): fail-fast output domain
  • Typed-state-with-coupled-diagnostics (lower + infer): structural output domain

Both fixes landed in PR #3138 (multiple post-merge findings across PB-2/3/4/5 L2.5 docs consolidated). 21 post-merge findings total addressed.

Already replied multiple times on this PR per the BLOCKING relay queue. PR #3138 is the canonical fix-forward; this finding is duplicate of /api/reviews/12175 cluster.

— sent from zesty-bear-812 (gunbc Director)

briansrls added a commit that referenced this pull request May 15, 2026
…:Let + SurfaceLiteral span correction

Cursor INLINE BLOCKING line:151: §11 claimed "every Surface
variant carries SourceSpan" but live parse_surface.dag has:
- SurfaceItem::Let { name, type_ann, expr } — no direct span
- SurfaceLiteral = Int(String) | Bool(Bool) | String(String) —
  plain-tuple variants with no direct span

Source-span provenance for these cases is via enclosing carrier:
SurfaceLiteral wraps within `Literal { value, span }` at
parse_surface.dag:150. Let-item inherits container span.

INVARIANTS P2/P3 source provenance is structurally guaranteed
via direct-OR-enclosing carrier, but my "every variant"
overstatement obscured this.

Fix: §11 corrected to "most Surface variants carry SourceSpan
directly" + explicit Let + SurfaceLiteral exceptions noted +
Step 2 PR scope audits whether exceptions are structural-honest
(enclosing-carrier-provides-span) OR require substrate extension.

Same recurring overstatement class as earlier "every SurfaceItem
maps 1:1 to Declaration" (commit 61e2b67) — need to grep live
substrate variant fields BEFORE claiming uniform shape.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@briansrls

Copy link
Copy Markdown
Contributor Author

Cursor INLINE BLOCKING line:241 — finding is INCORRECT after verification.

Cursor's claim: "git ls-tree origin/main returned no blobs for those paths" (referring to docs/design-lower-stage-l25-model.md and docs/design-infer-stage-l25-model.md).

Verified live state (git ls-tree origin/main docs/design-lower-stage-l25-model.md docs/design-infer-stage-l25-model.md):

100644 blob 3197721b1076396996fd0bfc69eb804a3d109ee8	docs/design-infer-stage-l25-model.md
100644 blob 440101dc697b1e9579545ffb3c268fe04c671a2e	docs/design-lower-stage-l25-model.md

Both files ARE on origin/main (merged via PR #3077 at 2026-05-15T00:21:19Z + PR #3085 at 00:21:29Z). The cross-stage diagnostic pattern IS a repo authority — §16 primary-authority cite is correct.

Reviewer-side context appears stale (possibly comparing against an older base or before the 2026-05-15 merge of PR #3077/#3085). Same reviewer-stale-context class as earlier fixes: List<Correction> claim that didn't exist on live HEAD.

No fix-forward needed; cite is correct.

— sent from zesty-bear-812 (gunbc Director)

@briansrls

Copy link
Copy Markdown
Contributor Author

Codex high-level BLOCKING (sha 41ec0a7) — both findings already addressed.

Finding 1 (Surface provenance audit against live carriers) — addressed in PR #3138 commit cd6e8d1 (just landed).

§11 corrected from "every Surface variant carries SourceSpan" to "most Surface variants carry SourceSpan directly; SurfaceItem::Let + SurfaceLiteral variants lack direct span (provenance via enclosing Literal carrier at parse_surface.dag:150 OR Let inherits container span); Step 2 PR scope audits whether exceptions are structural-honest OR require substrate extension".

Finding 2 (Cross-stage pattern from PR-number lore vs repo authority) — finding INCORRECT after verification.

git ls-tree origin/main docs/design-lower-stage-l25-model.md docs/design-infer-stage-l25-model.md:

100644 blob 3197721b...	docs/design-infer-stage-l25-model.md
100644 blob 440101dc...	docs/design-lower-stage-l25-model.md

Both L2.5 docs ARE on origin/main (merged via PR #3077 + #3085 at 2026-05-15T00:21Z). The cross-stage pattern IS a live repo authority, not just PR-number lore. Reviewer-side context appears stale (comparing against pre-merge base).

Same reviewer-stale-context class as earlier fixes: List<Correction> phantom-claim that didn't exist on live HEAD + the git ls-tree returned no blobs claim at /api/reviews/12315 line:241. Both verified against live state; cites are correct.

— sent from zesty-bear-812 (gunbc Director)

briansrls added a commit that referenced this pull request May 15, 2026
…ncept, not carrier

Earlier draft (now-merged PR #3126) framed `GrammarSpec` as a second declared
`.dag` input type alongside `List<Token>`. Verified via grep that no
`type GrammarSpec` exists anywhere under src/v3/ or dsl/ — the repo carries
only `parse_tables.dag`'s 6 SG-2c table-families. Per cursor 2026-05-14T23:30:04Z
inline finding, this violates INVARIANTS P2 (the Step-2 signature names a
carrier the substrate doesn't declare).

Reframed §3 (and downstream mentions in §3.2, §3 preamble line:33, §4.2
codex-correction recap line:165, §5.1 line:181, §12 Q6 line:344) so that:

- Parse has ONE input at the API boundary: `List<Token>`.
- "GrammarSpec" is a concept-level grouping for the 6 compile-time table-families
  in `parse_tables.dag`, not a substrate carrier and not a runtime parameter.
- Step-2 signature stays `fn parse(tokens: List<Token>) -> Result<SurfaceModule, ParseDiagnostic>`
  per cfe842b (already applied in #3126); these edits remove the lingering
  "two input types" framing that contradicted that signature.

Per Decision 3.B (b) compile-time parser tables: substrate authority is
parse_tables.dag (6 table-families) consumed via direct table lookups inside
the parser body — no runtime grammar value, no `GrammarSpec` carrier needed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request May 15, 2026
…ng resolved by PR #3077 merge

Cursor inline BLOCKING at docs/design-parse-stage-l25-model.md:119 (sha at
merge time of PR #3126) flagged a real internal contradiction:
- §6 (lines 191, 207, 308) claimed "Step 2 (pipeline-slot declaration) is
  unblocked"
- §7.2 (line 227) claimed "PR #3077 §12 Q7 must ratify before any Step 2
  worker brief authoring"

A worker reading the doc could land Step 2 (pipeline boundary) before the
diagnostic carrier's P2/P3 failure shape was fixed.

Resolution: PR #3077 (PB-4 lower L2.5) merged at 2026-05-15T00:21:19Z,
carrying the §12 Q7 ratification of the Decision 2.B per-stage diagnostic
extension path. The gate IS now satisfied at HEAD, so the resolution is
fact-update (annotate Q7 as DONE with the merge timestamp) rather than
retracting either §6 or §7.2.

Edits:
- §15 step 4: annotated "DONE 2026-05-15T00:21:19Z when PR #3077 merged"
  and added the explicit "Step 2 is now genuinely unblocked, not just
  procedurally next" framing so workers reading the sequence don't bypass
  the gate.
- §7.2 line 227: rewritten from "Q7 must ratify before Step 2 brief
  authoring" (future tense, the contradiction surface) to "Gate satisfied
  2026-05-15T00:21:19Z when PR #3077 merged; Step 2 worker brief authoring
  is unblocked at HEAD per §15 step 4." Cites the cursor finding as the
  resolution path.

§6 unblocking statements stay as-is — they were correct at HEAD; the
contradiction lived in §7.2's pre-merge framing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request May 15, 2026
…tep 2 unblocking claim

Codex BLOCKING finding 2 (sha 16d21f4, 216s thinking): the Q7 dependency
was recorded in §7.2/§15 but not in the other Step-2-unblocking sites at
§6 lines 191, 207, 308 — risking a worker reading "Step 2 unblocked" without
also reading the Q7 prerequisite.

Codex framing: "make Q7 a hard precondition wherever Step 2 is called
unblocked, or split Step 2 into pre-Q7 and post-Q7 scopes with separate
receipts."

Chose the first option since PR #3077 has already merged (2026-05-15T00:21:19Z)
and splitting into pre/post-Q7 scopes is no longer load-bearing. Annotated
all three §6 sites:
- Line 191 (Implication for PB-3 migration): cites gate + merge timestamp
  + explicit "must NOT be brief-authored before that merge timestamp."
- Line 207 (Critical observation): cites the Step 2 gate as PR #3077 §12 Q7
  + merge timestamp + P3 failure-shape consequence if violated.
- Line 308 (Director-recommend phase list): cites gate + §7.2/§15 step 4
  cross-refs + merge timestamp.

Codex BLOCKING finding 1 (GrammarSpec carrier non-existence) verified
already resolved at HEAD via commit c97dc15 — every GrammarSpec mention
now explicitly marks it as a concept-not-carrier; Step 2 signature is
`fn parse(tokens: List<Token>) -> Result<SurfaceModule, ParseDiagnostic>`
with no GrammarSpec parameter.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request May 15, 2026
…icity + Q1 ratification-pending status

openai-pro REQUEST_CHANGES on PR #3126 sha 16d21f4 flagged three findings.
Findings 1 + 2 (signature vs realization mismatch under LAYER MODEL + P2/P3
boundary discipline) were already resolved at HEAD by earlier fix-forward
commits — Step 2 signature is now `fn parse(tokens: List<Token>) ->
Result<SurfaceModule, ParseDiagnostic>` matching live `parse_generated.rs:138`
with no GrammarSpec parameter and no diagnostics-coupled SurfaceModule
extension (§4.3 Result-sum disposition).

Finding 6 (TRACKED vs UNTRACKED DEBT — Step 3b/4 same-PR vs two-PR):
§9 had both a "Step 3b/4 COMBINED" row (line 250) and a leftover separate
"Step 4: Parity test" row (line 251) — internally contradictory. §15 also
still sequenced Steps 3b + 4 as four separate authoring/dispatch/ratify
beats (steps 12-17), contradicting §12 Q5's "same PR" decision and the
explicit "Update to §15" note at §12 line 325.

Resolution: collapsed §9 to one COMBINED row absorbing the parity-TestClaim
mechanics + P5 dissolution receipt from the deleted Step 4 row; collapsed
§15 steps 12-17 into single COMBINED authoring + dispatch + ratify (steps
12-14). Added explicit `feedback_paper_shrink_variants` reasoning in both
sections.

Finding 2.5 (PM intent — substrate-capability bundled vs separate):
§12 Q1 line 288 said "Director-recommend: (b) bundled" while §13 line 340
listed substrate-capability as a non-goal of PB-3 and §15 step 11 had
"WAIT for substrate-capability landing" — three sections, two different
execution paths.

Resolution: annotated Q1 as "PENDING operator/PM ratification" with
explicit default-execution clause: until operator ratifies, the doc
treats substrate-capability as path (a) separate lane (matching §13 + §15
+ §9 row). If/when ratified to (b), §13 drops the non-goal and §15 step 11
collapses into the COMBINED Step 3b/4 brief.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@briansrls

Copy link
Copy Markdown
Contributor Author

Status reply for the openai-pro review at sha 16d21f4 (review id 12337, BLOCKING with four findings). PR #3126 is already merged; the substantive findings were carried into fix-forward branch docs/director-l25-postmerge-cleanups (PR #3138). Mapping:

  • Finding 1 (LAYER MODEL — signature vs realization) + Finding 2 (P2/P3 boundary): resolved at fix-forward HEAD. Step 2 signature is now fn parse(tokens: List<Token>) -> Result<SurfaceModule, ParseDiagnostic> with no GrammarSpec parameter and no SurfaceModule diagnostics-extension. §4.3 (commit a76f421) drops the typed-state coupling proposal; §3 (commit c97dc15) makes parse_tables.dag's 6 SG-2c table-families the explicit authority and removes GrammarSpec from the signature.
  • Finding 6 (TRACKED vs UNTRACKED DEBT — Step 3b/4 same-PR vs two-PR): resolved at commit 46e3004. §9 row collapsed to one COMBINED Step 3b/4 (parity TestClaim + parse body deletion atomic in one PR); §15 steps 12-17 collapsed to single COMBINED authoring+dispatch+ratify (steps 12-14).
  • Finding 2.5 (PM intent — substrate-capability bundled vs separate): resolved at commit 46e3004. §12 Q1 annotated "PENDING operator/PM ratification" with explicit default-execution clause: until ratified, the doc treats substrate-capability as path (a) separate lane (matching §13 non-goal and §15 step-11 wait-gate). Bundling activates only on explicit ratification.

No further fixes needed against this review id on this merged PR; the parse L2.5 doc at PR #3138 HEAD reflects all four. Dashboard please stop re-relaying review id 12337.

— sent from zesty-bear-812

briansrls added a commit that referenced this pull request May 15, 2026
… single enumerated authority

Codex caught me copying the prose summary at parse_tables.dag:23-29 (which
enumerates only SG-2c-numbered families) instead of grepping the live
`^type [A-Z]` declarations. Result: SoftKeywordIdentRow (line 334) was
missing from §3.2 / §5.1 / §6 / §12 because it lacks an SG-2c-N number
in the prose summary.

Per `feedback_parallel_representation_debt`: structural fix is to stop
hand-enumerating in the doc — cite parse_tables.dag itself as the single
enumerated authority and use `type`-declaration line-anchors for the
worked example, not a hand-maintained count.

Edits:
- §3.2 §"Live substrate authority": replaced the SG-2c-numbered bullet
  list with `type`-declaration line-anchor enumeration including
  SoftKeywordIdentRow at parse_tables.dag:334 + the supporting enum
  BinaryOpLevel at line 133. Added codex-finding callout explaining the
  miss + the discipline shift.
- §3 preamble line:33, §3.2 line:45 callout, §3.2 line:57 framing,
  §3.2 §"Substrate authority" line:71, §5.1 line:171-180, §12 Q2 line:298,
  §12 Q6 line:334: all hardcoded "6 table-families" counts dropped; doc
  now points readers to §3.2 enumeration / `parse_tables.dag` directly.
- §5.1 sub-enumeration list (the parallel 6-item list at lines 173-178)
  deleted; replaced with redirect to §3.2 + restated 3a-vs-3b/4 scope split.

Code-level check before commit: `grep -nE '^type [A-Z]' src/v3/compiler/parse_tables.dag`
returns 7 types: BinaryOpLevel (133), BinaryOpRow (167), TopLevelItemKwRow (289),
SoftKeywordIdentRow (334), BracketRow (385), PrimaryPrefixRow (449),
PrimaryAtomRow (486). Doc enumeration matches.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@briansrls

Copy link
Copy Markdown
Contributor Author

Status reply for the cursor INLINE BLOCKING at docs/design-parse-stage-l25-model.md:65 (sha at merge time of PR #3126). Already addressed by fix-forward commit 3eeee0c on branch docs/director-l25-postmerge-cleanups (PR #3138):

  • SoftKeywordIdentRow is now enumerated in §3.2 at line 63 with the substrate line-anchor (parse_tables.dag:334).
  • The doc no longer hand-counts table-families; parse_tables.dag is the single enumerated authority. Eight prior "6 table-families" sites either dropped the count or redirect to §3.2's ^type line-anchor enumeration.
  • Codex BLOCKING (sha 5619afa) finding 1 + cursor INLINE BLOCKING line:65 are the same root-cause miss; both resolved by the same commit.

No further fixes needed against this inline on the merged PR; the parse L2.5 at PR #3138 HEAD reflects the enumerated authority. Dashboard please stop re-relaying this inline.

— sent from zesty-bear-812

briansrls added a commit that referenced this pull request May 15, 2026
…ratification (#3127)

* docs(r3): PB-2 tokenize pipeline-stage L2.5 domain model — DRAFT for ratification

Director-tier L2.5 model for PB-2 tokenize per operator 2026-05-14
ratification (Decision 1.A scoping = Option A).

PB-2 is the FURTHEST-ALONG pipeline stage — substrate authority
already lives in `.dag`:
- src/v3/std/tokenize.dag (Token + TokenKind taxonomy; LIVE 143
  lines)
- src/v3/compiler/tokenize.dag (tokenizer implementation; LIVE
  154 lines)
- src/v3/compiler/src/tokenize_generated.rs (AUTO-GENERATED; 362
  lines)

This is the END STATE that all other pipeline-stage migrations
target. PB-2 L2.5 is correspondingly lighter — mostly verification
+ residual hand-Rust retirement, NOT new substrate authoring.

Distinct §9 4-step framing:
- Step 3 = VERIFY substrate completeness (audit per
  feedback_paper_shrink_variants)
- Step 4 = HANDOFF/RETIRE residual hand-Rust scaffolding
  (coordinates with PB-Bootstrap-Process lane for codegen-driver
  retirement)

Captures audit dimensions explicitly:
- scanner-class definitions = declarative byte-pattern membership
- recognition tables = closed-axis enums
- state machine = structural transitions
- no V2 `pub mod tokenize` absorption check

§12 Q1: codegen-driver retirement scope — Director-recommend
PB-Bootstrap-Process handles all codegen-driver retirement
cross-cuttingly (not per-stage paper-shrink risk).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): §12.6 citation fix — tokenize is PB-2 lane scope per design-pure-bootstrap-zero.md

Per cursor PR #3085 finding: §12.6 explicitly tables only 4
pipeline-stage migrations (emit→lower→infer→parse); tokenize is
per design-pure-bootstrap-zero.md PB-2 lane. Same fix as PR #3085
commit 89fbd7a applied here.

INVARIANTS P1 — documentation must not overstate authority cites.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): preemptive fix for PR #3126 codex BLOCKING propagation — PB-2 live state honesty

Same class as codex INLINE BLOCKING #3126 finding 1 (live state
honesty for diagnostic coupling) applied preemptively to PB-2
tokenize L2.5.

PB-2 §4.3 had "diagnostics coupled INTO List<Token>" framing
which would overstate the live carrier shape (bare List<Token>
has no diagnostic field; tokenize_generated.rs:96 today returns
Result<Vec<Token>, Diagnostic>).

Fix: §4.3 reframed with PROPOSED substrate extension explicit —
new `TokenizedSource { tokens, diagnostics }` wrapper carrier as
the typed-state output. Step 2 brief includes wrapper authoring
in pipeline-slot PR scope.

Same discipline as PR #3126 commit bdff8c5.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3077 — fix PB-2 lane citation (design-pure-bootstrap.md not -zero.md)

Per cursor APPROVE_WITH_COMMENTS /api/reviews/12087: PB-2 lane is
defined in docs/design-pure-bootstrap.md §"PB-2 — tokenize retire"
(line ~134), NOT docs/design-pure-bootstrap-zero.md. The -zero.md
doc has Subsumed-lanes list with PB-1/PB-4/PB-5/PB-6 but NOT PB-2.

Propagated fix applies same cite-error correction as PR #3066 §1.8
discipline: cite the actual doc, not an adjacent doc with similar
name. INVARIANTS P2 single-authority-citation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): fix cursor PR #3127 BLOCKING contradictions + add §12 Q6

Cursor APPROVE_WITH_COMMENTS (/api/reviews/12093) caught two
substantive contradictions I introduced when adding TokenizedSource
in commit 2b9756b:

1. §4.3 vs §9 Step 2 signature mismatch — §4.3 said `-> TokenizedSource`
   but §9 Step 2 row still said `-> List<Token>`. Same
   `feedback_discipline_change_audit_all_contract_mentions` issue
   that's recurred 4x this session.

2. §4.3 referenced "§12 Q-new" but §12 only had Q1-Q5; broken anchor.

Fix:
1. §9 Step 2 row updated: signature `-> TokenizedSource` with
   wrapper carrier shape `{ tokens, diagnostics }` per §4.3
2. §4.3 anchor updated: "§12 Q6" (resolved)
3. Added §12 Q6: TokenizedSource carrier shape ratification —
   (a) wrapper record vs (b) per-Token diagnostic coupling;
   Director-recommend (a) for PB-3 SurfaceModule parallelism
4. §14 + §15 + §16 Q-list refs updated to Q1-Q6

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): fix codex BLOCKING PR #3127 — Token shape + Q4 audit boundary

Codex REQUEST_CHANGES (sha b881de2) with 2 substantive findings:

1. §4.1 Token shape claim "optional lexeme: String" — wrong per
   live substrate at src/v3/std/tokenize.dag:65-67. Live Token
   has 2 fields only (kind + span); lexeme-content lives ON the
   TokenKind variants (Ident(String) / IntLit(String) / etc.).

   Fix: corrected §4.1 to reflect live carrier shape; payloads
   on TokenKind variants noted explicitly.

2. §12 Q4 substrate-completeness audit scoped only to
   tokenize_generated.rs — missed the regen_tokenize codegen-
   driver boundary. If regen_tokenize carries scanner-logic
   decisions (rather than mechanical template-rendering of
   substrate facts), the substrate isn't complete — the driver
   IS hand-Rust scanner logic in disguise.

   Fix: Q4 audit extended with (d) regen_tokenize codegen-
   driver logic audit + (e) ROADMAP.md deferral row option per
   feedback_paper_shrink_variants P5 receipt discipline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): fix codex BLOCKING PR #3127 — TokenizeDiagnostic PROPOSED + scaffold disclosure

Codex REQUEST_CHANGES (sha b881de2, full body) caught 2 substantive
overstatements:

1. §2 line 46 claimed "tokenize failures produce typed
   TokenizeDiagnostic variants" — but live tokenize_generated.rs:96
   returns generic `Result<Vec<Token>, Diagnostic>` with
   `Diagnostic::TokenizerError { message, span, correction }`. Typed
   TokenizeDiagnostic is a PROPOSED extension, not live state.

   Fix: §2 reframed with live state explicit + TokenizeDiagnostic
   marked PROPOSED per PR #3077 §12 Q7 ratification path.

2. §1 line 22 + §6 + §9 Step 2 line 198 framed PB-2 as "mostly
   verification" — but live tokenize.dag:16-30+ has TWO explicit
   tracked scaffold zones:
   - SG-1a: regen_tokenize parses raw source text for
     dag_keyword_set / dag_operators (ValueBody::Unparsed)
   - Character-level under-consumption: StringEscapeSpec /
     LocalPunctSpec.pattern / string_literal_delimiter as opaque
     Strings; hidden Rust character predicates (byte.is_ascii_digit
     etc.) at tokenize_generated.rs:15-22 leaking through codegen

   Residual hand-Rust is NOT just the codegen artifact — it includes
   (a) regen_tokenize logic, (b) SG-1a raw-text-extractor scaffold,
   (c) character-predicate scaffold leaking through codegen.

   Fix: §1 + §6 + §9 Step 2 reframed honestly. PB-2 is "FURTHER
   ALONG but not complete"; Step 4 carries scaffold-retirement
   scope, not just codegen-artifact retirement.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): codex PR #3127 BLOCKING (review id 12370) — drop TokenizedSource + cite concrete P5 receipts

Codex review id 12370 on sha d15e1f2 raised two load-bearing planning-shape
findings. Both addressed; this commit ports the same edits already living on
fix-forward branch docs/director-l25-postmerge-cleanups (PR #3138 commit
6adb992) onto PR #3127's branch directly so codex BLOCKING resolves on
this PR's own HEAD rather than waiting on PR #3138 merge.

Finding 1 — parallel boundary carriers (INVARIANTS P2 / Practices 3+5):
§4.3 + §9 Step 2 + §12 Q6 named `TokenizedSource { tokens, diagnostics }`
as the output, while §2/§7.2/§7.3 named `List<Token>`. Same misclassification
removed from the parse L2.5 (PR #3138 §4.3): tokenize sits in the fail-fast
output domain alongside PB-3 parse + PB-6 emit (a partial token list with a
corrupt token in the middle is not a valid downstream input for parse), so
the failure couples via `Result`, not into the structural carrier.

Resolution:
- §4.3 rewritten to ratify `Result<List<Token>, TokenizeDiagnostic>` — the
  live `tokenize_generated.rs:96` shape — with no `TokenizedSource` extension.
- §9 Step 2 row signature updated to match; explicit "single canonical
  boundary carrier: List<Token> on the Ok branch" framing.
- §12 Q6 resolved REJECTED in-doc (no operator ratification needed;
  disposition follows from the cross-stage discriminator load-bearing in
  PR #3138 parse L2.5).
- §16 memory-disciplines bullets rewritten parallel to PR #3138 parse §16:
  Result-sum, no diagnostics field on `List<Token>`.
- §14 "Surfaces awaiting" trimmed Q6 from the operator-ratification list.

Finding 2 — soft deferral of `regen_tokenize` retirement (INVARIANTS P5):
deferral previously named "PB-Bootstrap-Process lane scope" without a
concrete ROADMAP.md row. Updated §9 Step 2 + Step 4 rows to cite the named
receipts:
- `docs/design-pure-bootstrap-zero.md:116` (PB-Bootstrap-Process lane:
  author bootstrap.dag + generated trampoline; sized M).
- `docs/design-pure-bootstrap-zero.md:118-123` (N=0 runtime verification
  gates).
- ROADMAP.md:467 (Character-level under-consumption in tokenize + syntax
  authorities — phase-2 char-class retype owns the codegen-driver path).
- ROADMAP.md:416 (Class 5 Gap 3 — top-level `ValueBody` boundary; gating
  substrate-capability for the phase-2 retype).
- ROADMAP.md:53 (T-PB-A — non-test census → 0 floor).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): codex PR #3138 BLOCKING (sha f08b952) Finding 1 — bind to live CharClass authority

Porting the same fix that landed on PR #3138 commit 367fdc2 onto PR #3127's
own branch so codex BLOCKING resolves on this PR's HEAD directly.

Codex Finding 1: §4.2 TokenizeDiagnostic + §5.1/§5.2 headings used
`ScannerCharClass` / `ScannerClassRef` — names that exist only in the
generated Rust enum spelling, not as a .dag substrate declaration. Live
authority is `dsl/std/unicode.dag:62` `type CharClass = Whitespace | Digit
| IdentStart | IdentContinue`, consumed at `src/v3/compiler/tokenize.dag:103`.

Resolution:
- §4.2: `expected_class: ScannerClassRef` → `expected_class: CharClass`;
  dropped the `type ScannerClassRef = ScannerCharClass` alias; added
  codex-finding callout citing the substrate authority.
- §5.1: heading + intro now cite `dsl/std/unicode.dag:62` directly.
- §5.2: heading "CharClass → token-recognition state machine".

Same failure-mode as `feedback_grep_substrate_before_naming_ratification`:
naming a substrate carrier without grep-verifying against live .dag.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3138 INLINE BLOCKING line:188 — §7.3 chain Ok-branch annotation

Same edit as PR #3138 commit a8c0ff7 ported to this PR's branch. §7.3
cross-stage chain now annotates Ok-branch propagation + Err-branch
fail-fast termination explicitly, eliminating the apparent contradiction
between §4.3 (Result-sum) and §7.3 (List<Token> in the chain). They were
already consistent — Ok-branch payload flows forward; Err terminates —
but the annotation makes it self-evident at §7.3.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): openai-pro PR #3127 BLOCKING (sha d15e1f2) — character-level scaffold dissolution trigger

Same edit as PR #3138 commit 5a93d93 ported to this PR's branch.
§1 item 2 character-level under-consumption scaffold now carries the
same SG-1a-shape dissolution trigger structure: substrate-consumption
condition (a) + codegen-driver condition (b) + same-PR delete receipt,
with cross-refs to §9 Step 4 gating prereqs already cited.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3127 APPROVE_WITH_COMMENTS — §14 + §15 Q6-already-rejected sweep

Same edit as PR #3138 commit 887c696 ported to this PR's branch. §14
acceptance criterion 11 + §15 step 1 now say "Q1-Q5" with explicit
Q6-rejected crossrefs, aligning with §12 Q6 + §14 "Surfaces awaiting"
which already said "Q1-Q5 only".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request May 15, 2026
…ctions (#3138)

* docs(r3): PB-2 tokenize pipeline-stage L2.5 domain model — DRAFT for ratification

Director-tier L2.5 model for PB-2 tokenize per operator 2026-05-14
ratification (Decision 1.A scoping = Option A).

PB-2 is the FURTHEST-ALONG pipeline stage — substrate authority
already lives in `.dag`:
- src/v3/std/tokenize.dag (Token + TokenKind taxonomy; LIVE 143
  lines)
- src/v3/compiler/tokenize.dag (tokenizer implementation; LIVE
  154 lines)
- src/v3/compiler/src/tokenize_generated.rs (AUTO-GENERATED; 362
  lines)

This is the END STATE that all other pipeline-stage migrations
target. PB-2 L2.5 is correspondingly lighter — mostly verification
+ residual hand-Rust retirement, NOT new substrate authoring.

Distinct §9 4-step framing:
- Step 3 = VERIFY substrate completeness (audit per
  feedback_paper_shrink_variants)
- Step 4 = HANDOFF/RETIRE residual hand-Rust scaffolding
  (coordinates with PB-Bootstrap-Process lane for codegen-driver
  retirement)

Captures audit dimensions explicitly:
- scanner-class definitions = declarative byte-pattern membership
- recognition tables = closed-axis enums
- state machine = structural transitions
- no V2 `pub mod tokenize` absorption check

§12 Q1: codegen-driver retirement scope — Director-recommend
PB-Bootstrap-Process handles all codegen-driver retirement
cross-cuttingly (not per-stage paper-shrink risk).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): §12.6 citation fix — tokenize is PB-2 lane scope per design-pure-bootstrap-zero.md

Per cursor PR #3085 finding: §12.6 explicitly tables only 4
pipeline-stage migrations (emit→lower→infer→parse); tokenize is
per design-pure-bootstrap-zero.md PB-2 lane. Same fix as PR #3085
commit 89fbd7a applied here.

INVARIANTS P1 — documentation must not overstate authority cites.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): preemptive fix for PR #3126 codex BLOCKING propagation — PB-2 live state honesty

Same class as codex INLINE BLOCKING #3126 finding 1 (live state
honesty for diagnostic coupling) applied preemptively to PB-2
tokenize L2.5.

PB-2 §4.3 had "diagnostics coupled INTO List<Token>" framing
which would overstate the live carrier shape (bare List<Token>
has no diagnostic field; tokenize_generated.rs:96 today returns
Result<Vec<Token>, Diagnostic>).

Fix: §4.3 reframed with PROPOSED substrate extension explicit —
new `TokenizedSource { tokens, diagnostics }` wrapper carrier as
the typed-state output. Step 2 brief includes wrapper authoring
in pipeline-slot PR scope.

Same discipline as PR #3126 commit bdff8c5.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3077 — fix PB-2 lane citation (design-pure-bootstrap.md not -zero.md)

Per cursor APPROVE_WITH_COMMENTS /api/reviews/12087: PB-2 lane is
defined in docs/design-pure-bootstrap.md §"PB-2 — tokenize retire"
(line ~134), NOT docs/design-pure-bootstrap-zero.md. The -zero.md
doc has Subsumed-lanes list with PB-1/PB-4/PB-5/PB-6 but NOT PB-2.

Propagated fix applies same cite-error correction as PR #3066 §1.8
discipline: cite the actual doc, not an adjacent doc with similar
name. INVARIANTS P2 single-authority-citation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): fix cursor PR #3127 BLOCKING contradictions + add §12 Q6

Cursor APPROVE_WITH_COMMENTS (/api/reviews/12093) caught two
substantive contradictions I introduced when adding TokenizedSource
in commit 2b9756b:

1. §4.3 vs §9 Step 2 signature mismatch — §4.3 said `-> TokenizedSource`
   but §9 Step 2 row still said `-> List<Token>`. Same
   `feedback_discipline_change_audit_all_contract_mentions` issue
   that's recurred 4x this session.

2. §4.3 referenced "§12 Q-new" but §12 only had Q1-Q5; broken anchor.

Fix:
1. §9 Step 2 row updated: signature `-> TokenizedSource` with
   wrapper carrier shape `{ tokens, diagnostics }` per §4.3
2. §4.3 anchor updated: "§12 Q6" (resolved)
3. Added §12 Q6: TokenizedSource carrier shape ratification —
   (a) wrapper record vs (b) per-Token diagnostic coupling;
   Director-recommend (a) for PB-3 SurfaceModule parallelism
4. §14 + §15 + §16 Q-list refs updated to Q1-Q6

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): fix codex BLOCKING PR #3127 — Token shape + Q4 audit boundary

Codex REQUEST_CHANGES (sha b881de2) with 2 substantive findings:

1. §4.1 Token shape claim "optional lexeme: String" — wrong per
   live substrate at src/v3/std/tokenize.dag:65-67. Live Token
   has 2 fields only (kind + span); lexeme-content lives ON the
   TokenKind variants (Ident(String) / IntLit(String) / etc.).

   Fix: corrected §4.1 to reflect live carrier shape; payloads
   on TokenKind variants noted explicitly.

2. §12 Q4 substrate-completeness audit scoped only to
   tokenize_generated.rs — missed the regen_tokenize codegen-
   driver boundary. If regen_tokenize carries scanner-logic
   decisions (rather than mechanical template-rendering of
   substrate facts), the substrate isn't complete — the driver
   IS hand-Rust scanner logic in disguise.

   Fix: Q4 audit extended with (d) regen_tokenize codegen-
   driver logic audit + (e) ROADMAP.md deferral row option per
   feedback_paper_shrink_variants P5 receipt discipline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): fix codex BLOCKING PR #3127 — TokenizeDiagnostic PROPOSED + scaffold disclosure

Codex REQUEST_CHANGES (sha b881de2, full body) caught 2 substantive
overstatements:

1. §2 line 46 claimed "tokenize failures produce typed
   TokenizeDiagnostic variants" — but live tokenize_generated.rs:96
   returns generic `Result<Vec<Token>, Diagnostic>` with
   `Diagnostic::TokenizerError { message, span, correction }`. Typed
   TokenizeDiagnostic is a PROPOSED extension, not live state.

   Fix: §2 reframed with live state explicit + TokenizeDiagnostic
   marked PROPOSED per PR #3077 §12 Q7 ratification path.

2. §1 line 22 + §6 + §9 Step 2 line 198 framed PB-2 as "mostly
   verification" — but live tokenize.dag:16-30+ has TWO explicit
   tracked scaffold zones:
   - SG-1a: regen_tokenize parses raw source text for
     dag_keyword_set / dag_operators (ValueBody::Unparsed)
   - Character-level under-consumption: StringEscapeSpec /
     LocalPunctSpec.pattern / string_literal_delimiter as opaque
     Strings; hidden Rust character predicates (byte.is_ascii_digit
     etc.) at tokenize_generated.rs:15-22 leaking through codegen

   Residual hand-Rust is NOT just the codegen artifact — it includes
   (a) regen_tokenize logic, (b) SG-1a raw-text-extractor scaffold,
   (c) character-predicate scaffold leaking through codegen.

   Fix: §1 + §6 + §9 Step 2 reframed honestly. PB-2 is "FURTHER
   ALONG but not complete"; Step 4 carries scaffold-retirement
   scope, not just codegen-artifact retirement.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): post-merge fix-forward — §16 + §9 Step 2 internal contradictions

Two post-merge doc-internal contradictions caught by reviewers
after operator merged PR #3077 / #3126 / #3085 at 2026-05-15T00:21Z.

**PR #3077 PB-4 lower §16 fix**:
§16 "Memory disciplines applied" bullet said "diagnostics coupled
INTO PreInferDag via biconditional" — but §4.3 (per openai-pro
DiagnosticAnchor fix commit b812db9) constrains biconditional
to PortAnchor-only. Other anchor kinds (DeclarationAnchor /
RecordFieldAnchor / SurfaceFormAnchor) couple without port-state.
Fix: §16 bullet honors §4.3 anchor-typed framing.

**PR #3126 PB-3 parse §9 Step 2 fix**:
§9 Step 2 row described diagnostics as "coupled INTO SurfaceModule"
as if live — §4.3 correctly marks it PROPOSED. Same
feedback_discipline_change_audit_all_contract_mentions pattern
that's recurred this session.
Fix: §9 Step 2 row clarified — "PROPOSED extension per §4.3";
Step 2 PR scope includes authoring the diagnostics field
extension, NOT a live coupling.

Per feedback_discipline_change_audit_all_contract_mentions: when
a substantive fix changes a discipline framing, audit ALL sections
(framing + contract + handoff). Post-merge audit surfaced these
residual contradictions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): post-merge fix-forward — PR #3126 codex BLOCKING (GrammarSpec parallel-authority + fail-closed weakening)

Codex REQUEST_CHANGES on already-merged PR #3126 (/api/reviews/12175):
2 substantive findings on the post-merge doc.

**Finding 1 (P2 violation — GrammarSpec parallel authority)**:

§3.2 says GrammarSpec is compile-time-only, NOT runtime-
interpreted (per Decision 3.B (b) operator override). But the
proposed stage contract still took `grammar: GrammarSpec` as
runtime input. Creates two authorities (compiled parser tables
+ runtime GrammarSpec value).

Fix: §4.3 signature reframed to `fn parse(tokens: List<Token>)
-> Result<SurfaceModule, ParseDiagnostic>` — NO runtime
GrammarSpec input. Compile-time generated parser tables consumed
via internal dispatch. Step 2 + Step 4 rows updated.

**Finding 2 (P3 + Practices 1/2 — fail-closed weakening)**:

Live parser at parse_generated.rs:138 returns `Result<SurfaceModule,
Diagnostic>` (fail-closed; aborts on first error). Earlier draft
proposed `SurfaceModule` with embedded diagnostics — would let
partial-parse states be constructible + let downstream observe
"success" output after parse failure. Violation of fail-closed
discipline.

Fix: signature preserves Result-sum (matches live + emit's
pattern). Distinguished cross-stage:
- Result-sum (parse + emit): fail-fast output domain
- Typed-state-with-coupled-diagnostics (lower + infer): structural
  output domain where partial-failure IS valid intermediate

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3126 post-merge APPROVE_WITH_COMMENTS — §4.1 + §16 fail-closed honesty

Cursor caught 2 more post-merge contradictions on PR #3126:

1. §4.1 line 81 "construction-time invariant" talks about
   "ParseDiagnostic in the diagnostic stream" tied to SurfaceModule
   path — but §5.2 + live parse_generated.rs:138 use
   Result<SurfaceModule, Diagnostic>. §4.1 reads as claim about
   today's plumbing.

   Fix: §4.1 reframed — live boundary explicit (Result-sum);
   construction-time invariant scoped to Ok-arm SurfaceModule +
   Err-arm ParseDiagnostic, no partial-parse with embedded
   diagnostics.

2. §16 line 397 cites C-8 as "ParseDiagnostic coupled INTO
   SurfaceModule" without qualifier — but §4.3 (post codex
   REQUEST_CHANGES fix) constrains to Result-sum.

   Fix: §16 bullet honors §4.3 Result-sum framing; cross-stage
   discriminator named.

Same recurring feedback_discipline_change_audit_all_contract_mentions
pattern — substantive fix to §4.3 + §9 Step 2 left §4.1 + §16
inconsistent. Post-merge audit catches.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3085 INLINE BLOCKING — TypeConnective extension stop-signal

Cursor INLINE BLOCKING caught §3.2 line 66 "rules extend
automatically" weakens substrate-extension stop-signal. Thesis
discipline: a 7th TypeConnective variant requires explicit C1
audit + named infer-rule receipt.

Fix: §3.2 reframed. New TypeConnective variants do NOT extend
automatically; require explicit C1 substrate-extension audit +
named infer-rule receipt for the new variant's structural
inference behavior.

Per-variant structural facts means new variants need new
per-variant facts, NOT silent inheritance.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3085 INLINE BLOCKING — AlgebraAxis + InferDiagnostic Practice 4 classification

Cursor INLINE BLOCKING /api/reviews/12218 (line:112): proposed
substrate coproducts (AlgebraAxis + InferDiagnostic) lack
🟢/🟡/🔴 classification + ledger/trigger per modeling-discipline
Practice 4 (Coproduct dissolution).

Fix: added 🟡 SCAFFOLD classification + named dissolution
trigger for both:

AlgebraAxis 🟡 SCAFFOLD:
- Trigger: Step 2 brief enumerates full algebra-axiom set
  against infer.rs check sites + verifies coverage parity
  with live verification.dag:146 AlgebraicLawKind 3-variant
  subset → promote to 🟢 TERMINAL.

InferDiagnostic 🟡 SCAFFOLD:
- Trigger: Step 2 brief enumerates full variant set against
  parse_generated.rs / lower.rs / infer.rs diagnostic emission
  sites → promote to 🟢 TERMINAL.
- Anti-bridge per Q6.5: does NOT collapse into
  CompilerDiagnosticKind without substrate-extension
  ratification per PR #3077 §12 Q7.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3077 INLINE BLOCKING — §5.1 SurfaceItem allocation correction

Cursor INLINE BLOCKING /api/reviews/12251 line:130: §5.1 said
"every SurfaceItem variant maps 1:1 to a Declaration placeholder"
but live lower.rs:2950-2958 explicitly skips Let/Module/Import
in collect_symbols.

Verified via Read of lower.rs:2956-2958:
  SurfaceItem::Let { .. } => continue,
  SurfaceItem::Module { .. } => continue,
  SurfaceItem::Import { .. } => continue,

Fix: §5.1 reframed — DeclarationAllocating variants (Fn /
FnExternalBody / Data / TypeAtom / TypeRecord) map to
placeholders; NonDeclarationAllocating variants (Let / Module /
Import) skip allocation per live lower.rs behavior.

Let-bodies lower to Bind expressions in Pass 2; Module/Import
are parsed-facts preserved but un-declared.

Earlier "every SurfaceItem variant" framing overstated; would
have steered Step 2/3 worker into wrong allocation contract.
Per INVARIANTS P1/P2 live-state honesty + facts-flow-forward.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3077 INLINE BLOCKING — ElaborationSpec scope broadened

Cursor INLINE BLOCKING line:33: ElaborationSpec was defined only
as Surface→Behavior recipe mapping, but lower constructs
Declarations / TypeConnectives / BranchPatterns / Bindings as
well. Non-Behavior lowering decisions outside declared authority
violates THESIS substrate ownership + INVARIANTS P2.

Fix: §3.2 ElaborationSpec scope broadened to ALL lowering
decisions:

1. SurfaceItem → Declaration recipes (Fn / Data / Type variants +
   Let/Module/Import skip-allocation per §5.1)
2. SurfaceType → TypeConnective recipes (Atom / Arrow / Compose /
   Disj construction)
3. SurfaceExpr → Behavior recipes (Value / Transform / Branch /
   Loop / Bind construction)
4. SurfacePattern → BranchPattern recipes (ResolvedVariant /
   UnresolvedVariant / record-pattern construction)
5. Binding-site rules (Bind params + result_port construction)

ElaborationSpec is single-authority across ALL axes; no axis
lives in implementation-tier hand-Rust.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3126 APPROVE_WITH_COMMENTS — §7.1 ordering vs independence clarification

Cursor APPROVE_WITH_COMMENTS /api/reviews/12265 line 197: §7.1
mixed two claims:
- "parse migrates AFTER tokenize substrate-side stable" (ordering)
- "PB-3 parse migration is independent of PB-2 tokenize migration
  status" (independence)

Read as contradictory by reviewers. Need one coherent story.

Fix: §7.1 reframed with two distinct axes explicit:

1. Substrate-stability ordering (SELF_HOSTING.md §2 bottom-up):
   tokenize Token carrier shape must be stable BEFORE parse
   migrates. Already true at HEAD (tokenize.dag:65-67 declares
   live carrier). ✓

2. Migration-timing independence (parallel-dispatch axis): PB-3
   parse migration ships in parallel with PB-2 residual-retirement
   work (SG-1a + character-level scaffold + codegen-driver
   retirement per PB-2 L2.5 §1). What parse needs is the stable
   Token CARRIER; PB-2's migration is about retiring residual
   hand-Rust, not changing the carrier.

Both claims coherent on the axis split; not contradictory.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3126 INLINE BLOCKING — ParseDiagnostic SourceSpan structural requirement

Cursor INLINE BLOCKING /api/reviews/12277 line:65: ParseDiagnostic
variants like UnexpectedToken lacked SourceSpan field;
List<ParseDiagnostic> cannot satisfy fail-closed source
attribution structurally without span on every variant.
INVARIANTS P2/P3 violation.

Fix: every ParseDiagnostic variant now carries SourceSpan
structurally:
- UnexpectedToken: added span: SourceSpan
- UnterminatedConstruct: opener_span: SourceSpan (already present)
- InvalidLiteral: added span: SourceSpan
- DuplicateRecordFieldLabel: added span: SourceSpan (current site)
  + prior_span: SourceSpan (prior site; both required)

Per INVARIANTS P2/P3 fail-closed source attribution discipline:
every diagnostic emission carries structural source-span
provenance; not optional.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3126 INLINE BLOCKING — Token authority cite phantom-reference fix

Cursor INLINE BLOCKING /api/reviews/12279 line:29: §3.1 cited
`src/v3/compiler/src/tokenize.rs` as "current hand-Rust" for
Token carrier — but `tokenize.rs` (without _generated suffix)
doesn't exist. Live state has tokenize.dag (live substrate) +
tokenize_generated.rs (codegen artifact).

Per design-pure-bootstrap.md PB-2 lane: tokenize retire has
substantially landed. The reference was an earlier-draft
phantom from when Token-was-hand-Rust framing was the assumption.

Fix: §3.1 reframed — Token type lives in LIVE
src/v3/std/tokenize.dag:65-67 shared taxonomy; tokenizer
implementation also live at src/v3/compiler/tokenize.dag (154
lines); codegen artifact at tokenize_generated.rs. tokenize.rs
phantom reference removed explicitly. PB-2 substantially landed
per design-pure-bootstrap.md; residual scaffold-retirement
scope per PB-2 L2.5 PR #3127.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3126 INLINE BLOCKING — Step 2 pipeline-slot target fix (compiler.dag → pipeline.dag)

Cursor INLINE BLOCKING /api/reviews/12281 line:138: §9 Step 2
referenced generic "compiler.dag" but dsl/gunbc/compiler.dag:24
explicitly directs internal pipeline (Tokenize → Parse → ...)
to src/v3/compiler/pipeline.dag, NOT generic compiler.dag.

Worker briefs authored against this doc would target the wrong
file for pipeline-slot declaration. P2 single-authority violation.

Fix: §9 Step 2 row in ALL 4 L2.5 docs (PB-2 / PB-3 / PB-4 / PB-5)
updated:
- "declared in compiler.dag" → "declared in src/v3/compiler/pipeline.dag (per dsl/gunbc/compiler.dag:24 — internal pipeline lives in pipeline.dag, NOT generic compiler.dag)"
- substrate column: "compiler.dag refinement" → "pipeline.dag refinement"
- §13 "Step 2 (pipeline-slot in compiler.dag)" → "pipeline-slot in src/v3/compiler/pipeline.dag"

Same phantom-citation class as the tokenize.rs phantom (commit
8ae37b4): I cited generic file path without verifying which
specific file is authoritative per project structure. Should
have grep'd dsl/gunbc/compiler.dag header notes before authoring.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3126 INLINE BLOCKING — Step 3b/4 phasing P5 receipt unambiguity

Cursor INLINE BLOCKING /api/reviews/12283 line:181: Q5 said
Step 3b "full parser body .dag migration + parser body deletion
in same PR", but §15 sequence schedules Step 4 parity/deletion
AFTER Step 3b merges. P5 dissolution receipt ambiguous.

If Step 3b lands .dag parser body BEFORE Step 4 deletes Rust
parse() body, Rust + .dag parser bodies coexist temporarily —
paper-shrink-relocation risk per feedback_paper_shrink_variants.

Fix:
1. §9 Step 3b row reframed as "Step 3b/4 COMBINED" — atomic
   single PR (full .dag parser body + parity TestClaim +
   parse_generated.rs:138 deletion + census shrink). Cannot land
   .dag parser body before Rust deletion.
2. §12 Q5 phasing clarified:
   - Phase 3a (separate PR): grammar table extension; P5 receipt
     = ROADMAP deferral row naming Step 3b/4 as future-receipt
   - Phase 3b/4 COMBINED (single PR): atomic substrate substitution
3. §9 + §15 update notes: sequence collapses steps 12-17 into
   single dispatch+merge for combined phase

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): codex PR #3126 high-level BLOCKING findings 1 + 2

Codex high-level BLOCKING (sha 140eb6b) had 4 findings:
- Findings 3 + 4 already addressed in PR #3138 commits 0159773
  + a1607a8
- Findings 1 + 2 addressed in this commit

**Finding 1 (Diagnostic kind/record conflated)**:
§4.2 ParseDiagnostic was modeled as variants-directly with span
+ kind-fields mixed. Live Diagnostic at diagnostics.dag:150 uses
record-wraps-kind pattern (`{ kind, span, message, correction }`).
Need consistent shape.

Fix: refactored to record-wraps-kind:
- `type ParseDiagnostic { kind: ParseDiagnosticKind, span: SourceSpan }`
- `type ParseDiagnosticKind = UnexpectedToken | UnterminatedConstruct | InvalidLiteral | DuplicateRecordFieldLabel | ...`

Span lives on ParseDiagnostic record (single source of truth);
variant-specific spans (opener_span / prior_span) remain on kind
variants where meaningful.

**Finding 2 (PB-2 §6 obsolete sibling-lane assumption)**:
§6 line 198 said "PB-2 Tokenize | src/v3/std/tokenize.dag (NEW
per PB-2 L2.5)" — but tokenize.dag is ALREADY LIVE per
design-pure-bootstrap.md §"PB-2 — tokenize retire" (substantially
landed).

Fix: §6 prereq table row updated to reflect LIVE state. PB-2's
residual scope is scaffold-retirement (SG-1a + character-level +
codegen-driver per PB-2 L2.5 §1), not carrier authoring. PB-3
consumes the live Token carrier; carrier shape stable across
PB-2 residual-retirement timing.

Findings 3 + 4 already addressed:
- Finding 3 (pipeline.dag target): commit 0159773
- Finding 4 (Step 3b/4 atomic vs sequential): commit a1607a8

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3126 APPROVE_WITH_COMMENTS — phantom "module-level metadata" removed

Cursor APPROVE_WITH_COMMENTS line:79: §4.1 said "SurfaceModule
(verified live) carries List<SurfaceItem> + module-level
metadata" — but live parse_surface.dag:29 has ONLY
`{ items: List<SurfaceItem> }`. No metadata fields.

Phantom addition violated INVARIANTS P1 live-state honesty.

Fix: §4.1 reframed to match live carrier exactly. Same
phantom-addition class as tokenize.rs phantom (commit 8ae37b4).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): codex PR #3085 high-level BLOCKING findings — AtomPayload 5-variant + diagnostic-table PROPOSED

Codex high-level BLOCKING (sha bf4d315) — 2 substantive findings:

**Finding 1 (AtomPayload stale)**:
§2 + §5 cited infer.rs:10 top-comment "Atom(Identifier { name,
resolved })" — but live substrate.dag:87 has 5-variant
AtomPayload sum: Literal | UnresolvedIdentifier |
ResolvedByStructure | ResolvedByName | TypeParam.

infer.rs top-comment is STALE vs live substrate. My doc inherited
the drift.

Fix: §2 enumeration corrected to all 5 AtomPayload variants per
live substrate.dag:87.

**Finding 2 (diagnostic-table PROPOSED, not live)**:
§2 + §4.1 + §4.3 said "diagnostics.contains(port_id)
biconditional" as if live — but Dag at substrate.dag:525 has
ONLY { declarations, nodes, ports, clusters }. NO diagnostics
field. Diagnostic-table is PROPOSED substrate extension.

Fix: §2 fail-closed note flagged PROPOSED — Step 2 PR scope
includes `diagnostics: Map<PortId, Diagnostic>` field extension
to Dag, OR PB-Substrate prereq adds it before PB-5 dispatch.

Same recurring feedback_grep_carrier_field_before_coupling_claim
discipline (PR #3126 SurfaceModule analogous case); needed to
grep type Dag fields BEFORE claiming the diagnostics field
exists.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3085 INLINE BLOCKING line:94 — §4.1 + §4.3 PROPOSED diagnostic-table marking

Cursor INLINE BLOCKING line:94: §4.1 + §4.3 said "diagnostics
coupled INTO InferredDag" without flagging the diagnostic-table
as a substrate extension. Live Dag at substrate.dag:525 has
{ declarations, nodes, ports, clusters } — NO diagnostics field.
Earlier commit c0d96af added PROPOSED marking only in §2;
§4.1 + §4.3 needed same treatment.

Fix: §4.1 + §4.3 reframed with explicit PROPOSED substrate-
extension marking + reference to §2 for extension scope.
Construction-time invariant + structural coupling are both
contingent on the substrate-extension landing (Step 2 PR scope
or PB-Substrate prereq).

Same recurring feedback_grep_carrier_field_before_coupling_claim
discipline applied to §4.1 + §4.3 consistently with §2.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): codex PR #3077 high-level BLOCKING — Practice 4 classifications for PB-4 coproducts

Codex high-level BLOCKING (sha b812db9): "Diagnostic substrate
shape was repaired around anchoring but not re-audited as new
substrate type declarations" — meaning DiagnosticAnchor +
LowerDiagnostic + SurfaceFormRef + IdentifierRef need
🟢/🟡/🔴 classifications per modeling-discipline Practice 4
(Coproduct dissolution).

Same pattern as PB-5 fix in commit 040681f (AlgebraAxis +
InferDiagnostic) applied here.

Fix: added classifications + dissolution triggers:

- SurfaceFormRef 🟢 TERMINAL: closed-axis sum over live Surface*
  carriers; no further dissolution.
- IdentifierRef 🟡 SCAFFOLD: dissolution trigger = Step 2 brief
  enumerates full identifier-kind set against lower.rs
  identifier-resolution sites; promote to 🟢 TERMINAL when
  SurfaceVarRef + TypePathRef + ModulePathRef cover actual axes.
- LowerDiagnostic 🟡 SCAFFOLD: dissolution trigger = Step 2 brief
  enumerates variant set against lower.rs Diagnostic emission
  sites + Q6.5 anti-bridge preserved + PR #3077 §12 Q7
  ratification path.
- DiagnosticAnchor 🟢 TERMINAL: closed-axis covering all
  lowering-stage anchor kinds; no further dissolution.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3077 INLINE BLOCKING line:161 — DiagnosticSource Practice 4 classification

Cursor inline finding adds DiagnosticSource to Practice 4
classification scope. Earlier commit aba79a1 classified
SurfaceFormRef + IdentifierRef + LowerDiagnostic + DiagnosticAnchor
but missed DiagnosticSource.

Fix: DiagnosticSource 🟢 TERMINAL at pipeline-stage
discrimination scope. Closed-axis sum (Parse | Lower | Infer |
Emit); adding new pipeline stage requires explicit substrate-
extension audit per Practice 4 + stop-signal discipline (same
shape as PB-5 §3.2 TypeConnective stop-signal).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3126 INLINE BLOCKING line:151 — §11 SurfaceItem::Let + SurfaceLiteral span correction

Cursor INLINE BLOCKING line:151: §11 claimed "every Surface
variant carries SourceSpan" but live parse_surface.dag has:
- SurfaceItem::Let { name, type_ann, expr } — no direct span
- SurfaceLiteral = Int(String) | Bool(Bool) | String(String) —
  plain-tuple variants with no direct span

Source-span provenance for these cases is via enclosing carrier:
SurfaceLiteral wraps within `Literal { value, span }` at
parse_surface.dag:150. Let-item inherits container span.

INVARIANTS P2/P3 source provenance is structurally guaranteed
via direct-OR-enclosing carrier, but my "every variant"
overstatement obscured this.

Fix: §11 corrected to "most Surface variants carry SourceSpan
directly" + explicit Let + SurfaceLiteral exceptions noted +
Step 2 PR scope audits whether exceptions are structural-honest
(enclosing-carrier-provides-span) OR require substrate extension.

Same recurring overstatement class as earlier "every SurfaceItem
maps 1:1 to Declaration" (commit 61e2b67) — need to grep live
substrate variant fields BEFORE claiming uniform shape.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* WIP: gunbc Director

* docs(r3): cursor PR #3126 INLINE BLOCKING line:32 — GrammarSpec is concept, not carrier

Earlier draft (now-merged PR #3126) framed `GrammarSpec` as a second declared
`.dag` input type alongside `List<Token>`. Verified via grep that no
`type GrammarSpec` exists anywhere under src/v3/ or dsl/ — the repo carries
only `parse_tables.dag`'s 6 SG-2c table-families. Per cursor 2026-05-14T23:30:04Z
inline finding, this violates INVARIANTS P2 (the Step-2 signature names a
carrier the substrate doesn't declare).

Reframed §3 (and downstream mentions in §3.2, §3 preamble line:33, §4.2
codex-correction recap line:165, §5.1 line:181, §12 Q6 line:344) so that:

- Parse has ONE input at the API boundary: `List<Token>`.
- "GrammarSpec" is a concept-level grouping for the 6 compile-time table-families
  in `parse_tables.dag`, not a substrate carrier and not a runtime parameter.
- Step-2 signature stays `fn parse(tokens: List<Token>) -> Result<SurfaceModule, ParseDiagnostic>`
  per cfe842b (already applied in #3126); these edits remove the lingering
  "two input types" framing that contradicted that signature.

Per Decision 3.B (b) compile-time parser tables: substrate authority is
parse_tables.dag (6 table-families) consumed via direct table lookups inside
the parser body — no runtime grammar value, no `GrammarSpec` carrier needed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): codex PR #3138 BLOCKING — §4.3 + §16 internal contradictions resolved

Codex review id 12391 on sha cd6e8d1 flagged two live statements of the
already-rejected typed-state-with-coupled-diagnostics model still sitting
inside the parse L2.5, contradicting the corrected Result-sum framing in §4.2
and §6 Step 2:

1. §4.3 still proposed a `SurfaceModule { items, diagnostics }` extension
   modeled on PB-4/PB-5 patterns. Reframed: §4.3 now states explicitly that
   parse-stage uses Result-sum (no diagnostics field on SurfaceModule),
   restates the cross-stage discriminator (Result-sum for fail-fast output
   domains: parse + emit; typed-state for structural output domains: lower +
   infer), and cites `parse_generated.rs:138` as the live shape.

2. §16 "Memory disciplines applied" bullet read
   "feedback_state_space_vs_behavioral_invariants (typed-state SurfaceModule
   at output)". Rewritten to "parse output is `Result<SurfaceModule,
   ParseDiagnostic>` — the type rules out partial-parse states by
   construction; SurfaceModule itself carries no diagnostic field per §4.3".

Per `feedback_discipline_change_audit_all_contract_mentions`: when a
contract changes (here: SurfaceModule extension dropped in favor of
Result-sum), all §-internal restatements must be swept in the same diff
or they leak through as authoritative parallel claims.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): codex PR #3127 BLOCKING — drop TokenizedSource extension + cite concrete P5 receipts

Codex review id 12370 on sha d15e1f2 raised two load-bearing planning-shape
findings on the tokenize L2.5. Addressed in this fix-forward branch (PR #3138)
since PR #3127 is still open but accumulating cycles.

Finding 1 — parallel boundary carriers (INVARIANTS P2 / Modeling Practices 3+5):
§4.3 + §9 Step 2 + §12 Q6 named `TokenizedSource { tokens, diagnostics }` as the
output, while §2/§7.2/§7.3 named `List<Token>`. Same misclassification I just
removed from the parse L2.5 in PR #3138 §4.3: tokenize sits in the fail-fast
output domain alongside PB-3 parse + PB-6 emit (a partial token list with a
corrupt token in the middle is not a valid downstream input for parse), so the
failure couples via `Result`, not into the structural carrier.

Resolution:
- §4.3 rewritten to ratify `Result<List<Token>, TokenizeDiagnostic>` — the live
  `tokenize_generated.rs:96` shape — with no `TokenizedSource` extension.
- §9 Step 2 row signature updated to match; explicit "single canonical boundary
  carrier: List<Token> on the Ok branch" framing.
- §12 Q6 resolved REJECTED in-doc (no operator ratification needed; disposition
  follows from the cross-stage discriminator that's also load-bearing in PR
  #3138 parse L2.5).
- §16 memory-disciplines bullets rewritten parallel to PR #3138 parse §16:
  Result-sum, no diagnostics field on `List<Token>`.
- §14 "Surfaces awaiting" trimmed Q6 from the operator-ratification list.

Finding 2 — soft deferral of `regen_tokenize` retirement (INVARIANTS P5):
deferral previously named "PB-Bootstrap-Process lane scope" without a concrete
ROADMAP.md row. Updated §9 Step 2 + Step 4 rows to cite the named receipts:
- `docs/design-pure-bootstrap-zero.md:116` (PB-Bootstrap-Process lane: author
  bootstrap.dag + generated trampoline; sized M).
- `docs/design-pure-bootstrap-zero.md:118-123` (N=0 runtime verification gates).
- ROADMAP.md:467 (Character-level under-consumption in tokenize + syntax
  authorities — phase-2 char-class retype owns the codegen-driver path).
- ROADMAP.md:416 (Class 5 Gap 3 — top-level `ValueBody` boundary; gating
  substrate-capability for the phase-2 retype).
- ROADMAP.md:53 (T-PB-A — non-test census → 0 floor).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3126 BLOCKING line:119 — §6/§7.2/§15 Q7 sequencing resolved by PR #3077 merge

Cursor inline BLOCKING at docs/design-parse-stage-l25-model.md:119 (sha at
merge time of PR #3126) flagged a real internal contradiction:
- §6 (lines 191, 207, 308) claimed "Step 2 (pipeline-slot declaration) is
  unblocked"
- §7.2 (line 227) claimed "PR #3077 §12 Q7 must ratify before any Step 2
  worker brief authoring"

A worker reading the doc could land Step 2 (pipeline boundary) before the
diagnostic carrier's P2/P3 failure shape was fixed.

Resolution: PR #3077 (PB-4 lower L2.5) merged at 2026-05-15T00:21:19Z,
carrying the §12 Q7 ratification of the Decision 2.B per-stage diagnostic
extension path. The gate IS now satisfied at HEAD, so the resolution is
fact-update (annotate Q7 as DONE with the merge timestamp) rather than
retracting either §6 or §7.2.

Edits:
- §15 step 4: annotated "DONE 2026-05-15T00:21:19Z when PR #3077 merged"
  and added the explicit "Step 2 is now genuinely unblocked, not just
  procedurally next" framing so workers reading the sequence don't bypass
  the gate.
- §7.2 line 227: rewritten from "Q7 must ratify before Step 2 brief
  authoring" (future tense, the contradiction surface) to "Gate satisfied
  2026-05-15T00:21:19Z when PR #3077 merged; Step 2 worker brief authoring
  is unblocked at HEAD per §15 step 4." Cites the cursor finding as the
  resolution path.

§6 unblocking statements stay as-is — they were correct at HEAD; the
contradiction lived in §7.2's pre-merge framing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): codex PR #3126 BLOCKING (sha 16d21f4) — Q7 cited at every Step 2 unblocking claim

Codex BLOCKING finding 2 (sha 16d21f4, 216s thinking): the Q7 dependency
was recorded in §7.2/§15 but not in the other Step-2-unblocking sites at
§6 lines 191, 207, 308 — risking a worker reading "Step 2 unblocked" without
also reading the Q7 prerequisite.

Codex framing: "make Q7 a hard precondition wherever Step 2 is called
unblocked, or split Step 2 into pre-Q7 and post-Q7 scopes with separate
receipts."

Chose the first option since PR #3077 has already merged (2026-05-15T00:21:19Z)
and splitting into pre/post-Q7 scopes is no longer load-bearing. Annotated
all three §6 sites:
- Line 191 (Implication for PB-3 migration): cites gate + merge timestamp
  + explicit "must NOT be brief-authored before that merge timestamp."
- Line 207 (Critical observation): cites the Step 2 gate as PR #3077 §12 Q7
  + merge timestamp + P3 failure-shape consequence if violated.
- Line 308 (Director-recommend phase list): cites gate + §7.2/§15 step 4
  cross-refs + merge timestamp.

Codex BLOCKING finding 1 (GrammarSpec carrier non-existence) verified
already resolved at HEAD via commit c97dc15 — every GrammarSpec mention
now explicitly marks it as a concept-not-carrier; Step 2 signature is
`fn parse(tokens: List<Token>) -> Result<SurfaceModule, ParseDiagnostic>`
with no GrammarSpec parameter.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): openai-pro PR #3126 BLOCKING (sha 16d21f4) — Step 3b/4 atomicity + Q1 ratification-pending status

openai-pro REQUEST_CHANGES on PR #3126 sha 16d21f4 flagged three findings.
Findings 1 + 2 (signature vs realization mismatch under LAYER MODEL + P2/P3
boundary discipline) were already resolved at HEAD by earlier fix-forward
commits — Step 2 signature is now `fn parse(tokens: List<Token>) ->
Result<SurfaceModule, ParseDiagnostic>` matching live `parse_generated.rs:138`
with no GrammarSpec parameter and no diagnostics-coupled SurfaceModule
extension (§4.3 Result-sum disposition).

Finding 6 (TRACKED vs UNTRACKED DEBT — Step 3b/4 same-PR vs two-PR):
§9 had both a "Step 3b/4 COMBINED" row (line 250) and a leftover separate
"Step 4: Parity test" row (line 251) — internally contradictory. §15 also
still sequenced Steps 3b + 4 as four separate authoring/dispatch/ratify
beats (steps 12-17), contradicting §12 Q5's "same PR" decision and the
explicit "Update to §15" note at §12 line 325.

Resolution: collapsed §9 to one COMBINED row absorbing the parity-TestClaim
mechanics + P5 dissolution receipt from the deleted Step 4 row; collapsed
§15 steps 12-17 into single COMBINED authoring + dispatch + ratify (steps
12-14). Added explicit `feedback_paper_shrink_variants` reasoning in both
sections.

Finding 2.5 (PM intent — substrate-capability bundled vs separate):
§12 Q1 line 288 said "Director-recommend: (b) bundled" while §13 line 340
listed substrate-capability as a non-goal of PB-3 and §15 step 11 had
"WAIT for substrate-capability landing" — three sections, two different
execution paths.

Resolution: annotated Q1 as "PENDING operator/PM ratification" with
explicit default-execution clause: until operator ratifies, the doc
treats substrate-capability as path (a) separate lane (matching §13 + §15
+ §9 row). If/when ratified to (b), §13 drops the non-goal and §15 step 11
collapses into the COMBINED Step 3b/4 brief.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): codex PR #3126 BLOCKING (sha 5619afa) — parse_tables.dag as single enumerated authority

Codex caught me copying the prose summary at parse_tables.dag:23-29 (which
enumerates only SG-2c-numbered families) instead of grepping the live
`^type [A-Z]` declarations. Result: SoftKeywordIdentRow (line 334) was
missing from §3.2 / §5.1 / §6 / §12 because it lacks an SG-2c-N number
in the prose summary.

Per `feedback_parallel_representation_debt`: structural fix is to stop
hand-enumerating in the doc — cite parse_tables.dag itself as the single
enumerated authority and use `type`-declaration line-anchors for the
worked example, not a hand-maintained count.

Edits:
- §3.2 §"Live substrate authority": replaced the SG-2c-numbered bullet
  list with `type`-declaration line-anchor enumeration including
  SoftKeywordIdentRow at parse_tables.dag:334 + the supporting enum
  BinaryOpLevel at line 133. Added codex-finding callout explaining the
  miss + the discipline shift.
- §3 preamble line:33, §3.2 line:45 callout, §3.2 line:57 framing,
  §3.2 §"Substrate authority" line:71, §5.1 line:171-180, §12 Q2 line:298,
  §12 Q6 line:334: all hardcoded "6 table-families" counts dropped; doc
  now points readers to §3.2 enumeration / `parse_tables.dag` directly.
- §5.1 sub-enumeration list (the parallel 6-item list at lines 173-178)
  deleted; replaced with redirect to §3.2 + restated 3a-vs-3b/4 scope split.

Code-level check before commit: `grep -nE '^type [A-Z]' src/v3/compiler/parse_tables.dag`
returns 7 types: BinaryOpLevel (133), BinaryOpRow (167), TopLevelItemKwRow (289),
SoftKeywordIdentRow (334), BracketRow (385), PrimaryPrefixRow (449),
PrimaryAtomRow (486). Doc enumeration matches.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): codex PR #3138 BLOCKING (sha f08b952) — bind TokenizeDiagnostic to live CharClass authority

Codex Finding 1 (sha f08b952, 216s thinking): the §4.2 TokenizeDiagnostic
draft and the §5.1/§5.2 headings used `ScannerCharClass` / `ScannerClassRef`
— names that exist only as the *generated Rust enum spelling*, not as a
declared .dag substrate type. Verified via grep:

  grep -rn '^type CharClass\|^type ScannerC' dsl/ src/v3/

returns ONE authority: `dsl/std/unicode.dag:62`
  type CharClass = Whitespace | Digit | IdentStart | IdentContinue

consumed at `src/v3/compiler/tokenize.dag:103`
  data ascii_scan_order: List<CharClass> = [Whitespace, Digit, IdentStart, IdentContinue]

There is no `ScannerCharClass` declaration anywhere — that name was copied
from generated Rust without grep-verification, the same failure mode as
`feedback_grep_substrate_before_naming_ratification` (carrier-name
collision discipline).

Resolution:
- §4.2 TokenizeDiagnostic carrier: `expected_class: ScannerClassRef` →
  `expected_class: CharClass`, dropped the `type ScannerClassRef =
  ScannerCharClass` alias entirely; added a codex-finding callout citing
  the substrate authority + naming the failure mode.
- §5.1 heading "Byte → ScannerCharClass dispatch" → "Byte → CharClass
  dispatch"; bullets unchanged; added line-anchor cites for the substrate
  authority + explicit "NOT ScannerCharClass" disclaimer.
- §5.2 heading "ScannerCharClass → token-recognition state machine" →
  "CharClass → token-recognition state machine".

Finding 2 (TokenizedSource not reconciled with parse input contract): no
new fix required — already resolved by commit 6adb992 (TokenizedSource
extension dropped entirely; tokenize uses Result<List<Token>,
TokenizeDiagnostic>; List<Token> is the single canonical boundary carrier
consumed by parse). Codex was reviewing sha f08b952, which predated the
TokenizedSource drop.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3138 INLINE BLOCKING line:188 — clarify §7.3 chain is Ok-branch propagation

Cursor INLINE at sha f08b952 worried that §7.3's cross-stage chain
"tokenize → List<Token> → parse → ..." was inconsistent with §4.3's
TokenizedSource carrier (diagnostics not flowing forward). At HEAD the
TokenizedSource extension is dropped (commit 6adb992); tokenize uses
Result<List<Token>, TokenizeDiagnostic>, so List<Token> IS the canonical
Ok-branch payload that flows forward and Err branches terminate the
pipeline fail-fast.

To make this explicit at §7.3 (instead of leaving readers to infer it
from §4.3), annotated the chain with:
- "Ok-branch propagation; Err branches are stage-terminal fail-fast per
  §4.3 Result-sum discriminator" framing prefix.
- Per-stage Result/typed-state annotations: tokenize/parse show
  Result<Ok, Err>; lower/infer show typed-state structural-output;
  emit shows Result<EmittedArtifact, EmissionDiagnostic>.
- Explicit "on any stage's Err branch the pipeline aborts at that stage
  (no partial-output propagation across boundaries)" trailer.

This makes the chain self-consistent vis-a-vis §4.3 without requiring
the reader to walk back-and-forth, and prevents future readers from
re-introducing a TokenizedSource-shaped extension to "make diagnostics
flow forward" — they already do, just via the Err branch terminating
the pipeline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): openai-pro PR #3127 BLOCKING (sha d15e1f2) — character-level scaffold dissolution trigger

openai-pro REQUEST_CHANGES on sha d15e1f2: §1 line:26 character-level
under-consumption scaffold named the problem but lacked a checkable
dissolution trigger. SG-1a scaffold above had the right shape — "once
those bodies lower structurally under compile_to_dag, delete the raw-text
extractor + derive directly from lowered Dag in same PR." Character-level
scaffold just said "PB-2 Step 4 carries this scope" — a lane assignment,
not a trigger.

Resolution: rewrote §1 item 2 with the same SG-1a-shape trigger structure:
- Substrate-consumption condition (a): scanner classes / string escape /
  local punctuation retype to `dsl/std/unicode.dag` `CharClass` /
  `char_in_class` (concrete field retypes named:
  `StringEscapeSpec.suffix: Char`, `LocalPunctSpec.pattern: List<Char>`,
  `string_literal_delimiter: Char`).
- Codegen-driver condition (b): `tokenize_generated.rs` no longer emits
  hidden `byte.is_ascii_*` predicates because the driver reads class
  facts structurally from lowered `tokenize.dag`.
- Same-PR dissolution: delete the parallel character-predicate scaffold
  in the same PR that flips substrate consumption — no Rust-and-`.dag`
  coexistence per `feedback_paper_shrink_variants`.
- Cross-ref to §9 Step 4 gating prereqs: ROADMAP.md:467 + ROADMAP.md:416
  Class 5 Gap 3 + std.unicode bootstrap/load-set decision (already cited
  in §9 from earlier commit 6adb992).

Per openai-pro's framing: "small fix — mirror the SG-1a scaffold wording
by naming the exact substrate-consumption condition and same-PR deletion
receipt for the hidden Rust character predicates."

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* WIP: gunbc Director

* docs(r3): cursor PR #3127 APPROVE_WITH_COMMENTS — §14 + §15 Q6-already-rejected sweep

Cursor review id 12405 (APPROVE_WITH_COMMENTS) caught the same
`feedback_discipline_change_audit_all_contract_mentions` failure mode
recurring: §12 Q6 was resolved REJECTED in commit 6adb992, and §14
"Surfaces awaiting" + §12 Q6 heading + §9 Step 2 row were updated, but
two §-internal contract restatements were missed:

- §14 acceptance criterion 11: "Operator/PM ratification on §12 Q1-Q6"
- §15 step 1: "Operator / PM-delegate ratifies §12 Q1-Q6"

Both contradicted §12 Q6 + §14 "Surfaces awaiting" (which already said
"Q1-Q5 only"). A worker reading §14/§15 could schedule sign-offs on Q6
after it was already resolved-rejected elsewhere.

Resolution: both sites now say "Q1–Q5" with the explicit Q6-rejected
crossref + "see §14/§15 for same scoping" pointer at the §14 criterion
so the three sections agree internally.

Cursor verdict was APPROVE_WITH_COMMENTS (substantive APPROVE — "fix the
checklist/sequence so every section agrees Q6 is closed"); the
exploratory volatile-line-anchor note is harmless and out-of-scope for
this PR.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request May 15, 2026
…r inline Q7 sweep (#3140)

* docs(r3): PB-2 tokenize pipeline-stage L2.5 domain model — DRAFT for ratification

Director-tier L2.5 model for PB-2 tokenize per operator 2026-05-14
ratification (Decision 1.A scoping = Option A).

PB-2 is the FURTHEST-ALONG pipeline stage — substrate authority
already lives in `.dag`:
- src/v3/std/tokenize.dag (Token + TokenKind taxonomy; LIVE 143
  lines)
- src/v3/compiler/tokenize.dag (tokenizer implementation; LIVE
  154 lines)
- src/v3/compiler/src/tokenize_generated.rs (AUTO-GENERATED; 362
  lines)

This is the END STATE that all other pipeline-stage migrations
target. PB-2 L2.5 is correspondingly lighter — mostly verification
+ residual hand-Rust retirement, NOT new substrate authoring.

Distinct §9 4-step framing:
- Step 3 = VERIFY substrate completeness (audit per
  feedback_paper_shrink_variants)
- Step 4 = HANDOFF/RETIRE residual hand-Rust scaffolding
  (coordinates with PB-Bootstrap-Process lane for codegen-driver
  retirement)

Captures audit dimensions explicitly:
- scanner-class definitions = declarative byte-pattern membership
- recognition tables = closed-axis enums
- state machine = structural transitions
- no V2 `pub mod tokenize` absorption check

§12 Q1: codegen-driver retirement scope — Director-recommend
PB-Bootstrap-Process handles all codegen-driver retirement
cross-cuttingly (not per-stage paper-shrink risk).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): §12.6 citation fix — tokenize is PB-2 lane scope per design-pure-bootstrap-zero.md

Per cursor PR #3085 finding: §12.6 explicitly tables only 4
pipeline-stage migrations (emit→lower→infer→parse); tokenize is
per design-pure-bootstrap-zero.md PB-2 lane. Same fix as PR #3085
commit 89fbd7a applied here.

INVARIANTS P1 — documentation must not overstate authority cites.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): preemptive fix for PR #3126 codex BLOCKING propagation — PB-2 live state honesty

Same class as codex INLINE BLOCKING #3126 finding 1 (live state
honesty for diagnostic coupling) applied preemptively to PB-2
tokenize L2.5.

PB-2 §4.3 had "diagnostics coupled INTO List<Token>" framing
which would overstate the live carrier shape (bare List<Token>
has no diagnostic field; tokenize_generated.rs:96 today returns
Result<Vec<Token>, Diagnostic>).

Fix: §4.3 reframed with PROPOSED substrate extension explicit —
new `TokenizedSource { tokens, diagnostics }` wrapper carrier as
the typed-state output. Step 2 brief includes wrapper authoring
in pipeline-slot PR scope.

Same discipline as PR #3126 commit bdff8c5.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3077 — fix PB-2 lane citation (design-pure-bootstrap.md not -zero.md)

Per cursor APPROVE_WITH_COMMENTS /api/reviews/12087: PB-2 lane is
defined in docs/design-pure-bootstrap.md §"PB-2 — tokenize retire"
(line ~134), NOT docs/design-pure-bootstrap-zero.md. The -zero.md
doc has Subsumed-lanes list with PB-1/PB-4/PB-5/PB-6 but NOT PB-2.

Propagated fix applies same cite-error correction as PR #3066 §1.8
discipline: cite the actual doc, not an adjacent doc with similar
name. INVARIANTS P2 single-authority-citation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): fix cursor PR #3127 BLOCKING contradictions + add §12 Q6

Cursor APPROVE_WITH_COMMENTS (/api/reviews/12093) caught two
substantive contradictions I introduced when adding TokenizedSource
in commit 2b9756b:

1. §4.3 vs §9 Step 2 signature mismatch — §4.3 said `-> TokenizedSource`
   but §9 Step 2 row still said `-> List<Token>`. Same
   `feedback_discipline_change_audit_all_contract_mentions` issue
   that's recurred 4x this session.

2. §4.3 referenced "§12 Q-new" but §12 only had Q1-Q5; broken anchor.

Fix:
1. §9 Step 2 row updated: signature `-> TokenizedSource` with
   wrapper carrier shape `{ tokens, diagnostics }` per §4.3
2. §4.3 anchor updated: "§12 Q6" (resolved)
3. Added §12 Q6: TokenizedSource carrier shape ratification —
   (a) wrapper record vs (b) per-Token diagnostic coupling;
   Director-recommend (a) for PB-3 SurfaceModule parallelism
4. §14 + §15 + §16 Q-list refs updated to Q1-Q6

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): fix codex BLOCKING PR #3127 — Token shape + Q4 audit boundary

Codex REQUEST_CHANGES (sha b881de2) with 2 substantive findings:

1. §4.1 Token shape claim "optional lexeme: String" — wrong per
   live substrate at src/v3/std/tokenize.dag:65-67. Live Token
   has 2 fields only (kind + span); lexeme-content lives ON the
   TokenKind variants (Ident(String) / IntLit(String) / etc.).

   Fix: corrected §4.1 to reflect live carrier shape; payloads
   on TokenKind variants noted explicitly.

2. §12 Q4 substrate-completeness audit scoped only to
   tokenize_generated.rs — missed the regen_tokenize codegen-
   driver boundary. If regen_tokenize carries scanner-logic
   decisions (rather than mechanical template-rendering of
   substrate facts), the substrate isn't complete — the driver
   IS hand-Rust scanner logic in disguise.

   Fix: Q4 audit extended with (d) regen_tokenize codegen-
   driver logic audit + (e) ROADMAP.md deferral row option per
   feedback_paper_shrink_variants P5 receipt discipline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): fix codex BLOCKING PR #3127 — TokenizeDiagnostic PROPOSED + scaffold disclosure

Codex REQUEST_CHANGES (sha b881de2, full body) caught 2 substantive
overstatements:

1. §2 line 46 claimed "tokenize failures produce typed
   TokenizeDiagnostic variants" — but live tokenize_generated.rs:96
   returns generic `Result<Vec<Token>, Diagnostic>` with
   `Diagnostic::TokenizerError { message, span, correction }`. Typed
   TokenizeDiagnostic is a PROPOSED extension, not live state.

   Fix: §2 reframed with live state explicit + TokenizeDiagnostic
   marked PROPOSED per PR #3077 §12 Q7 ratification path.

2. §1 line 22 + §6 + §9 Step 2 line 198 framed PB-2 as "mostly
   verification" — but live tokenize.dag:16-30+ has TWO explicit
   tracked scaffold zones:
   - SG-1a: regen_tokenize parses raw source text for
     dag_keyword_set / dag_operators (ValueBody::Unparsed)
   - Character-level under-consumption: StringEscapeSpec /
     LocalPunctSpec.pattern / string_literal_delimiter as opaque
     Strings; hidden Rust character predicates (byte.is_ascii_digit
     etc.) at tokenize_generated.rs:15-22 leaking through codegen

   Residual hand-Rust is NOT just the codegen artifact — it includes
   (a) regen_tokenize logic, (b) SG-1a raw-text-extractor scaffold,
   (c) character-predicate scaffold leaking through codegen.

   Fix: §1 + §6 + §9 Step 2 reframed honestly. PB-2 is "FURTHER
   ALONG but not complete"; Step 4 carries scaffold-retirement
   scope, not just codegen-artifact retirement.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): post-merge fix-forward — §16 + §9 Step 2 internal contradictions

Two post-merge doc-internal contradictions caught by reviewers
after operator merged PR #3077 / #3126 / #3085 at 2026-05-15T00:21Z.

**PR #3077 PB-4 lower §16 fix**:
§16 "Memory disciplines applied" bullet said "diagnostics coupled
INTO PreInferDag via biconditional" — but §4.3 (per openai-pro
DiagnosticAnchor fix commit b812db9) constrains biconditional
to PortAnchor-only. Other anchor kinds (DeclarationAnchor /
RecordFieldAnchor / SurfaceFormAnchor) couple without port-state.
Fix: §16 bullet honors §4.3 anchor-typed framing.

**PR #3126 PB-3 parse §9 Step 2 fix**:
§9 Step 2 row described diagnostics as "coupled INTO SurfaceModule"
as if live — §4.3 correctly marks it PROPOSED. Same
feedback_discipline_change_audit_all_contract_mentions pattern
that's recurred this session.
Fix: §9 Step 2 row clarified — "PROPOSED extension per §4.3";
Step 2 PR scope includes authoring the diagnostics field
extension, NOT a live coupling.

Per feedback_discipline_change_audit_all_contract_mentions: when
a substantive fix changes a discipline framing, audit ALL sections
(framing + contract + handoff). Post-merge audit surfaced these
residual contradictions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): post-merge fix-forward — PR #3126 codex BLOCKING (GrammarSpec parallel-authority + fail-closed weakening)

Codex REQUEST_CHANGES on already-merged PR #3126 (/api/reviews/12175):
2 substantive findings on the post-merge doc.

**Finding 1 (P2 violation — GrammarSpec parallel authority)**:

§3.2 says GrammarSpec is compile-time-only, NOT runtime-
interpreted (per Decision 3.B (b) operator override). But the
proposed stage contract still took `grammar: GrammarSpec` as
runtime input. Creates two authorities (compiled parser tables
+ runtime GrammarSpec value).

Fix: §4.3 signature reframed to `fn parse(tokens: List<Token>)
-> Result<SurfaceModule, ParseDiagnostic>` — NO runtime
GrammarSpec input. Compile-time generated parser tables consumed
via internal dispatch. Step 2 + Step 4 rows updated.

**Finding 2 (P3 + Practices 1/2 — fail-closed weakening)**:

Live parser at parse_generated.rs:138 returns `Result<SurfaceModule,
Diagnostic>` (fail-closed; aborts on first error). Earlier draft
proposed `SurfaceModule` with embedded diagnostics — would let
partial-parse states be constructible + let downstream observe
"success" output after parse failure. Violation of fail-closed
discipline.

Fix: signature preserves Result-sum (matches live + emit's
pattern). Distinguished cross-stage:
- Result-sum (parse + emit): fail-fast output domain
- Typed-state-with-coupled-diagnostics (lower + infer): structural
  output domain where partial-failure IS valid intermediate

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3126 post-merge APPROVE_WITH_COMMENTS — §4.1 + §16 fail-closed honesty

Cursor caught 2 more post-merge contradictions on PR #3126:

1. §4.1 line 81 "construction-time invariant" talks about
   "ParseDiagnostic in the diagnostic stream" tied to SurfaceModule
   path — but §5.2 + live parse_generated.rs:138 use
   Result<SurfaceModule, Diagnostic>. §4.1 reads as claim about
   today's plumbing.

   Fix: §4.1 reframed — live boundary explicit (Result-sum);
   construction-time invariant scoped to Ok-arm SurfaceModule +
   Err-arm ParseDiagnostic, no partial-parse with embedded
   diagnostics.

2. §16 line 397 cites C-8 as "ParseDiagnostic coupled INTO
   SurfaceModule" without qualifier — but §4.3 (post codex
   REQUEST_CHANGES fix) constrains to Result-sum.

   Fix: §16 bullet honors §4.3 Result-sum framing; cross-stage
   discriminator named.

Same recurring feedback_discipline_change_audit_all_contract_mentions
pattern — substantive fix to §4.3 + §9 Step 2 left §4.1 + §16
inconsistent. Post-merge audit catches.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3085 INLINE BLOCKING — TypeConnective extension stop-signal

Cursor INLINE BLOCKING caught §3.2 line 66 "rules extend
automatically" weakens substrate-extension stop-signal. Thesis
discipline: a 7th TypeConnective variant requires explicit C1
audit + named infer-rule receipt.

Fix: §3.2 reframed. New TypeConnective variants do NOT extend
automatically; require explicit C1 substrate-extension audit +
named infer-rule receipt for the new variant's structural
inference behavior.

Per-variant structural facts means new variants need new
per-variant facts, NOT silent inheritance.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3085 INLINE BLOCKING — AlgebraAxis + InferDiagnostic Practice 4 classification

Cursor INLINE BLOCKING /api/reviews/12218 (line:112): proposed
substrate coproducts (AlgebraAxis + InferDiagnostic) lack
🟢/🟡/🔴 classification + ledger/trigger per modeling-discipline
Practice 4 (Coproduct dissolution).

Fix: added 🟡 SCAFFOLD classification + named dissolution
trigger for both:

AlgebraAxis 🟡 SCAFFOLD:
- Trigger: Step 2 brief enumerates full algebra-axiom set
  against infer.rs check sites + verifies coverage parity
  with live verification.dag:146 AlgebraicLawKind 3-variant
  subset → promote to 🟢 TERMINAL.

InferDiagnostic 🟡 SCAFFOLD:
- Trigger: Step 2 brief enumerates full variant set against
  parse_generated.rs / lower.rs / infer.rs diagnostic emission
  sites → promote to 🟢 TERMINAL.
- Anti-bridge per Q6.5: does NOT collapse into
  CompilerDiagnosticKind without substrate-extension
  ratification per PR #3077 §12 Q7.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3077 INLINE BLOCKING — §5.1 SurfaceItem allocation correction

Cursor INLINE BLOCKING /api/reviews/12251 line:130: §5.1 said
"every SurfaceItem variant maps 1:1 to a Declaration placeholder"
but live lower.rs:2950-2958 explicitly skips Let/Module/Import
in collect_symbols.

Verified via Read of lower.rs:2956-2958:
  SurfaceItem::Let { .. } => continue,
  SurfaceItem::Module { .. } => continue,
  SurfaceItem::Import { .. } => continue,

Fix: §5.1 reframed — DeclarationAllocating variants (Fn /
FnExternalBody / Data / TypeAtom / TypeRecord) map to
placeholders; NonDeclarationAllocating variants (Let / Module /
Import) skip allocation per live lower.rs behavior.

Let-bodies lower to Bind expressions in Pass 2; Module/Import
are parsed-facts preserved but un-declared.

Earlier "every SurfaceItem variant" framing overstated; would
have steered Step 2/3 worker into wrong allocation contract.
Per INVARIANTS P1/P2 live-state honesty + facts-flow-forward.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3077 INLINE BLOCKING — ElaborationSpec scope broadened

Cursor INLINE BLOCKING line:33: ElaborationSpec was defined only
as Surface→Behavior recipe mapping, but lower constructs
Declarations / TypeConnectives / BranchPatterns / Bindings as
well. Non-Behavior lowering decisions outside declared authority
violates THESIS substrate ownership + INVARIANTS P2.

Fix: §3.2 ElaborationSpec scope broadened to ALL lowering
decisions:

1. SurfaceItem → Declaration recipes (Fn / Data / Type variants +
   Let/Module/Import skip-allocation per §5.1)
2. SurfaceType → TypeConnective recipes (Atom / Arrow / Compose /
   Disj construction)
3. SurfaceExpr → Behavior recipes (Value / Transform / Branch /
   Loop / Bind construction)
4. SurfacePattern → BranchPattern recipes (ResolvedVariant /
   UnresolvedVariant / record-pattern construction)
5. Binding-site rules (Bind params + result_port construction)

ElaborationSpec is single-authority across ALL axes; no axis
lives in implementation-tier hand-Rust.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3126 APPROVE_WITH_COMMENTS — §7.1 ordering vs independence clarification

Cursor APPROVE_WITH_COMMENTS /api/reviews/12265 line 197: §7.1
mixed two claims:
- "parse migrates AFTER tokenize substrate-side stable" (ordering)
- "PB-3 parse migration is independent of PB-2 tokenize migration
  status" (independence)

Read as contradictory by reviewers. Need one coherent story.

Fix: §7.1 reframed with two distinct axes explicit:

1. Substrate-stability ordering (SELF_HOSTING.md §2 bottom-up):
   tokenize Token carrier shape must be stable BEFORE parse
   migrates. Already true at HEAD (tokenize.dag:65-67 declares
   live carrier). ✓

2. Migration-timing independence (parallel-dispatch axis): PB-3
   parse migration ships in parallel with PB-2 residual-retirement
   work (SG-1a + character-level scaffold + codegen-driver
   retirement per PB-2 L2.5 §1). What parse needs is the stable
   Token CARRIER; PB-2's migration is about retiring residual
   hand-Rust, not changing the carrier.

Both claims coherent on the axis split; not contradictory.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3126 INLINE BLOCKING — ParseDiagnostic SourceSpan structural requirement

Cursor INLINE BLOCKING /api/reviews/12277 line:65: ParseDiagnostic
variants like UnexpectedToken lacked SourceSpan field;
List<ParseDiagnostic> cannot satisfy fail-closed source
attribution structurally without span on every variant.
INVARIANTS P2/P3 violation.

Fix: every ParseDiagnostic variant now carries SourceSpan
structurally:
- UnexpectedToken: added span: SourceSpan
- UnterminatedConstruct: opener_span: SourceSpan (already present)
- InvalidLiteral: added span: SourceSpan
- DuplicateRecordFieldLabel: added span: SourceSpan (current site)
  + prior_span: SourceSpan (prior site; both required)

Per INVARIANTS P2/P3 fail-closed source attribution discipline:
every diagnostic emission carries structural source-span
provenance; not optional.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3126 INLINE BLOCKING — Token authority cite phantom-reference fix

Cursor INLINE BLOCKING /api/reviews/12279 line:29: §3.1 cited
`src/v3/compiler/src/tokenize.rs` as "current hand-Rust" for
Token carrier — but `tokenize.rs` (without _generated suffix)
doesn't exist. Live state has tokenize.dag (live substrate) +
tokenize_generated.rs (codegen artifact).

Per design-pure-bootstrap.md PB-2 lane: tokenize retire has
substantially landed. The reference was an earlier-draft
phantom from when Token-was-hand-Rust framing was the assumption.

Fix: §3.1 reframed — Token type lives in LIVE
src/v3/std/tokenize.dag:65-67 shared taxonomy; tokenizer
implementation also live at src/v3/compiler/tokenize.dag (154
lines); codegen artifact at tokenize_generated.rs. tokenize.rs
phantom reference removed explicitly. PB-2 substantially landed
per design-pure-bootstrap.md; residual scaffold-retirement
scope per PB-2 L2.5 PR #3127.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3126 INLINE BLOCKING — Step 2 pipeline-slot target fix (compiler.dag → pipeline.dag)

Cursor INLINE BLOCKING /api/reviews/12281 line:138: §9 Step 2
referenced generic "compiler.dag" but dsl/gunbc/compiler.dag:24
explicitly directs internal pipeline (Tokenize → Parse → ...)
to src/v3/compiler/pipeline.dag, NOT generic compiler.dag.

Worker briefs authored against this doc would target the wrong
file for pipeline-slot declaration. P2 single-authority violation.

Fix: §9 Step 2 row in ALL 4 L2.5 docs (PB-2 / PB-3 / PB-4 / PB-5)
updated:
- "declared in compiler.dag" → "declared in src/v3/compiler/pipeline.dag (per dsl/gunbc/compiler.dag:24 — internal pipeline lives in pipeline.dag, NOT generic compiler.dag)"
- substrate column: "compiler.dag refinement" → "pipeline.dag refinement"
- §13 "Step 2 (pipeline-slot in compiler.dag)" → "pipeline-slot in src/v3/compiler/pipeline.dag"

Same phantom-citation class as the tokenize.rs phantom (commit
8ae37b4): I cited generic file path without verifying which
specific file is authoritative per project structure. Should
have grep'd dsl/gunbc/compiler.dag header notes before authoring.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3126 INLINE BLOCKING — Step 3b/4 phasing P5 receipt unambiguity

Cursor INLINE BLOCKING /api/reviews/12283 line:181: Q5 said
Step 3b "full parser body .dag migration + parser body deletion
in same PR", but §15 sequence schedules Step 4 parity/deletion
AFTER Step 3b merges. P5 dissolution receipt ambiguous.

If Step 3b lands .dag parser body BEFORE Step 4 deletes Rust
parse() body, Rust + .dag parser bodies coexist temporarily —
paper-shrink-relocation risk per feedback_paper_shrink_variants.

Fix:
1. §9 Step 3b row reframed as "Step 3b/4 COMBINED" — atomic
   single PR (full .dag parser body + parity TestClaim +
   parse_generated.rs:138 deletion + census shrink). Cannot land
   .dag parser body before Rust deletion.
2. §12 Q5 phasing clarified:
   - Phase 3a (separate PR): grammar table extension; P5 receipt
     = ROADMAP deferral row naming Step 3b/4 as future-receipt
   - Phase 3b/4 COMBINED (single PR): atomic substrate substitution
3. §9 + §15 update notes: sequence collapses steps 12-17 into
   single dispatch+merge for combined phase

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): codex PR #3126 high-level BLOCKING findings 1 + 2

Codex high-level BLOCKING (sha 140eb6b) had 4 findings:
- Findings 3 + 4 already addressed in PR #3138 commits 0159773
  + a1607a8
- Findings 1 + 2 addressed in this commit

**Finding 1 (Diagnostic kind/record conflated)**:
§4.2 ParseDiagnostic was modeled as variants-directly with span
+ kind-fields mixed. Live Diagnostic at diagnostics.dag:150 uses
record-wraps-kind pattern (`{ kind, span, message, correction }`).
Need consistent shape.

Fix: refactored to record-wraps-kind:
- `type ParseDiagnostic { kind: ParseDiagnosticKind, span: SourceSpan }`
- `type ParseDiagnosticKind = UnexpectedToken | UnterminatedConstruct | InvalidLiteral | DuplicateRecordFieldLabel | ...`

Span lives on ParseDiagnostic record (single source of truth);
variant-specific spans (opener_span / prior_span) remain on kind
variants where meaningful.

**Finding 2 (PB-2 §6 obsolete sibling-lane assumption)**:
§6 line 198 said "PB-2 Tokenize | src/v3/std/tokenize.dag (NEW
per PB-2 L2.5)" — but tokenize.dag is ALREADY LIVE per
design-pure-bootstrap.md §"PB-2 — tokenize retire" (substantially
landed).

Fix: §6 prereq table row updated to reflect LIVE state. PB-2's
residual scope is scaffold-retirement (SG-1a + character-level +
codegen-driver per PB-2 L2.5 §1), not carrier authoring. PB-3
consumes the live Token carrier; carrier shape stable across
PB-2 residual-retirement timing.

Findings 3 + 4 already addressed:
- Finding 3 (pipeline.dag target): commit 0159773
- Finding 4 (Step 3b/4 atomic vs sequential): commit a1607a8

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3126 APPROVE_WITH_COMMENTS — phantom "module-level metadata" removed

Cursor APPROVE_WITH_COMMENTS line:79: §4.1 said "SurfaceModule
(verified live) carries List<SurfaceItem> + module-level
metadata" — but live parse_surface.dag:29 has ONLY
`{ items: List<SurfaceItem> }`. No metadata fields.

Phantom addition violated INVARIANTS P1 live-state honesty.

Fix: §4.1 reframed to match live carrier exactly. Same
phantom-addition class as tokenize.rs phantom (commit 8ae37b4).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): codex PR #3085 high-level BLOCKING findings — AtomPayload 5-variant + diagnostic-table PROPOSED

Codex high-level BLOCKING (sha bf4d315) — 2 substantive findings:

**Finding 1 (AtomPayload stale)**:
§2 + §5 cited infer.rs:10 top-comment "Atom(Identifier { name,
resolved })" — but live substrate.dag:87 has 5-variant
AtomPayload sum: Literal | UnresolvedIdentifier |
ResolvedByStructure | ResolvedByName | TypeParam.

infer.rs top-comment is STALE vs live substrate. My doc inherited
the drift.

Fix: §2 enumeration corrected to all 5 AtomPayload variants per
live substrate.dag:87.

**Finding 2 (diagnostic-table PROPOSED, not live)**:
§2 + §4.1 + §4.3 said "diagnostics.contains(port_id)
biconditional" as if live — but Dag at substrate.dag:525 has
ONLY { declarations, nodes, ports, clusters }. NO diagnostics
field. Diagnostic-table is PROPOSED substrate extension.

Fix: §2 fail-closed note flagged PROPOSED — Step 2 PR scope
includes `diagnostics: Map<PortId, Diagnostic>` field extension
to Dag, OR PB-Substrate prereq adds it before PB-5 dispatch.

Same recurring feedback_grep_carrier_field_before_coupling_claim
discipline (PR #3126 SurfaceModule analogous case); needed to
grep type Dag fields BEFORE claiming the diagnostics field
exists.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3085 INLINE BLOCKING line:94 — §4.1 + §4.3 PROPOSED diagnostic-table marking

Cursor INLINE BLOCKING line:94: §4.1 + §4.3 said "diagnostics
coupled INTO InferredDag" without flagging the diagnostic-table
as a substrate extension. Live Dag at substrate.dag:525 has
{ declarations, nodes, ports, clusters } — NO diagnostics field.
Earlier commit c0d96af added PROPOSED marking only in §2;
§4.1 + §4.3 needed same treatment.

Fix: §4.1 + §4.3 reframed with explicit PROPOSED substrate-
extension marking + reference to §2 for extension scope.
Construction-time invariant + structural coupling are both
contingent on the substrate-extension landing (Step 2 PR scope
or PB-Substrate prereq).

Same recurring feedback_grep_carrier_field_before_coupling_claim
discipline applied to §4.1 + §4.3 consistently with §2.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): codex PR #3077 high-level BLOCKING — Practice 4 classifications for PB-4 coproducts

Codex high-level BLOCKING (sha b812db9): "Diagnostic substrate
shape was repaired around anchoring but not re-audited as new
substrate type declarations" — meaning DiagnosticAnchor +
LowerDiagnostic + SurfaceFormRef + IdentifierRef need
🟢/🟡/🔴 classifications per modeling-discipline Practice 4
(Coproduct dissolution).

Same pattern as PB-5 fix in commit 040681f (AlgebraAxis +
InferDiagnostic) applied here.

Fix: added classifications + dissolution triggers:

- SurfaceFormRef 🟢 TERMINAL: closed-axis sum over live Surface*
  carriers; no further dissolution.
- IdentifierRef 🟡 SCAFFOLD: dissolution trigger = Step 2 brief
  enumerates full identifier-kind set against lower.rs
  identifier-resolution sites; promote to 🟢 TERMINAL when
  SurfaceVarRef + TypePathRef + ModulePathRef cover actual axes.
- LowerDiagnostic 🟡 SCAFFOLD: dissolution trigger = Step 2 brief
  enumerates variant set against lower.rs Diagnostic emission
  sites + Q6.5 anti-bridge preserved + PR #3077 §12 Q7
  ratification path.
- DiagnosticAnchor 🟢 TERMINAL: closed-axis covering all
  lowering-stage anchor kinds; no further dissolution.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3077 INLINE BLOCKING line:161 — DiagnosticSource Practice 4 classification

Cursor inline finding adds DiagnosticSource to Practice 4
classification scope. Earlier commit aba79a1 classified
SurfaceFormRef + IdentifierRef + LowerDiagnostic + DiagnosticAnchor
but missed DiagnosticSource.

Fix: DiagnosticSource 🟢 TERMINAL at pipeline-stage
discrimination scope. Closed-axis sum (Parse | Lower | Infer |
Emit); adding new pipeline stage requires explicit substrate-
extension audit per Practice 4 + stop-signal discipline (same
shape as PB-5 §3.2 TypeConnective stop-signal).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3126 INLINE BLOCKING line:151 — §11 SurfaceItem::Let + SurfaceLiteral span correction

Cursor INLINE BLOCKING line:151: §11 claimed "every Surface
variant carries SourceSpan" but live parse_surface.dag has:
- SurfaceItem::Let { name, type_ann, expr } — no direct span
- SurfaceLiteral = Int(String) | Bool(Bool) | String(String) —
  plain-tuple variants with no direct span

Source-span provenance for these cases is via enclosing carrier:
SurfaceLiteral wraps within `Literal { value, span }` at
parse_surface.dag:150. Let-item inherits container span.

INVARIANTS P2/P3 source provenance is structurally guaranteed
via direct-OR-enclosing carrier, but my "every variant"
overstatement obscured this.

Fix: §11 corrected to "most Surface variants carry SourceSpan
directly" + explicit Let + SurfaceLiteral exceptions noted +
Step 2 PR scope audits whether exceptions are structural-honest
(enclosing-carrier-provides-span) OR require substrate extension.

Same recurring overstatement class as earlier "every SurfaceItem
maps 1:1 to Declaration" (commit 61e2b67) — need to grep live
substrate variant fields BEFORE claiming uniform shape.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* WIP: gunbc Director

* docs(r3): cursor PR #3126 INLINE BLOCKING line:32 — GrammarSpec is concept, not carrier

Earlier draft (now-merged PR #3126) framed `GrammarSpec` as a second declared
`.dag` input type alongside `List<Token>`. Verified via grep that no
`type GrammarSpec` exists anywhere under src/v3/ or dsl/ — the repo carries
only `parse_tables.dag`'s 6 SG-2c table-families. Per cursor 2026-05-14T23:30:04Z
inline finding, this violates INVARIANTS P2 (the Step-2 signature names a
carrier the substrate doesn't declare).

Reframed §3 (and downstream mentions in §3.2, §3 preamble line:33, §4.2
codex-correction recap line:165, §5.1 line:181, §12 Q6 line:344) so that:

- Parse has ONE input at the API boundary: `List<Token>`.
- "GrammarSpec" is a concept-level grouping for the 6 compile-time table-families
  in `parse_tables.dag`, not a substrate carrier and not a runtime parameter.
- Step-2 signature stays `fn parse(tokens: List<Token>) -> Result<SurfaceModule, ParseDiagnostic>`
  per cfe842b (already applied in #3126); these edits remove the lingering
  "two input types" framing that contradicted that signature.

Per Decision 3.B (b) compile-time parser tables: substrate authority is
parse_tables.dag (6 table-families) consumed via direct table lookups inside
the parser body — no runtime grammar value, no `GrammarSpec` carrier needed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): codex PR #3138 BLOCKING — §4.3 + §16 internal contradictions resolved

Codex review id 12391 on sha cd6e8d1 flagged two live statements of the
already-rejected typed-state-with-coupled-diagnostics model still sitting
inside the parse L2.5, contradicting the corrected Result-sum framing in §4.2
and §6 Step 2:

1. §4.3 still proposed a `SurfaceModule { items, diagnostics }` extension
   modeled on PB-4/PB-5 patterns. Reframed: §4.3 now states explicitly that
   parse-stage uses Result-sum (no diagnostics field on SurfaceModule),
   restates the cross-stage discriminator (Result-sum for fail-fast output
   domains: parse + emit; typed-state for structural output domains: lower +
   infer), and cites `parse_generated.rs:138` as the live shape.

2. §16 "Memory disciplines applied" bullet read
   "feedback_state_space_vs_behavioral_invariants (typed-state SurfaceModule
   at output)". Rewritten to "parse output is `Result<SurfaceModule,
   ParseDiagnostic>` — the type rules out partial-parse states by
   construction; SurfaceModule itself carries no diagnostic field per §4.3".

Per `feedback_discipline_change_audit_all_contract_mentions`: when a
contract changes (here: SurfaceModule extension dropped in favor of
Result-sum), all §-internal restatements must be swept in the same diff
or they leak through as authoritative parallel claims.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): codex PR #3127 BLOCKING — drop TokenizedSource extension + cite concrete P5 receipts

Codex review id 12370 on sha d15e1f2 raised two load-bearing planning-shape
findings on the tokenize L2.5. Addressed in this fix-forward branch (PR #3138)
since PR #3127 is still open but accumulating cycles.

Finding 1 — parallel boundary carriers (INVARIANTS P2 / Modeling Practices 3+5):
§4.3 + §9 Step 2 + §12 Q6 named `TokenizedSource { tokens, diagnostics }` as the
output, while §2/§7.2/§7.3 named `List<Token>`. Same misclassification I just
removed from the parse L2.5 in PR #3138 §4.3: tokenize sits in the fail-fast
output domain alongside PB-3 parse + PB-6 emit (a partial token list with a
corrupt token in the middle is not a valid downstream input for parse), so the
failure couples via `Result`, not into the structural carrier.

Resolution:
- §4.3 rewritten to ratify `Result<List<Token>, TokenizeDiagnostic>` — the live
  `tokenize_generated.rs:96` shape — with no `TokenizedSource` extension.
- §9 Step 2 row signature updated to match; explicit "single canonical boundary
  carrier: List<Token> on the Ok branch" framing.
- §12 Q6 resolved REJECTED in-doc (no operator ratification needed; disposition
  follows from the cross-stage discriminator that's also load-bearing in PR
  #3138 parse L2.5).
- §16 memory-disciplines bullets rewritten parallel to PR #3138 parse §16:
  Result-sum, no diagnostics field on `List<Token>`.
- §14 "Surfaces awaiting" trimmed Q6 from the operator-ratification list.

Finding 2 — soft deferral of `regen_tokenize` retirement (INVARIANTS P5):
deferral previously named "PB-Bootstrap-Process lane scope" without a concrete
ROADMAP.md row. Updated §9 Step 2 + Step 4 rows to cite the named receipts:
- `docs/design-pure-bootstrap-zero.md:116` (PB-Bootstrap-Process lane: author
  bootstrap.dag + generated trampoline; sized M).
- `docs/design-pure-bootstrap-zero.md:118-123` (N=0 runtime verification gates).
- ROADMAP.md:467 (Character-level under-consumption in tokenize + syntax
  authorities — phase-2 char-class retype owns the codegen-driver path).
- ROADMAP.md:416 (Class 5 Gap 3 — top-level `ValueBody` boundary; gating
  substrate-capability for the phase-2 retype).
- ROADMAP.md:53 (T-PB-A — non-test census → 0 floor).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3126 BLOCKING line:119 — §6/§7.2/§15 Q7 sequencing resolved by PR #3077 merge

Cursor inline BLOCKING at docs/design-parse-stage-l25-model.md:119 (sha at
merge time of PR #3126) flagged a real internal contradiction:
- §6 (lines 191, 207, 308) claimed "Step 2 (pipeline-slot declaration) is
  unblocked"
- §7.2 (line 227) claimed "PR #3077 §12 Q7 must ratify before any Step 2
  worker brief authoring"

A worker reading the doc could land Step 2 (pipeline boundary) before the
diagnostic carrier's P2/P3 failure shape was fixed.

Resolution: PR #3077 (PB-4 lower L2.5) merged at 2026-05-15T00:21:19Z,
carrying the §12 Q7 ratification of the Decision 2.B per-stage diagnostic
extension path. The gate IS now satisfied at HEAD, so the resolution is
fact-update (annotate Q7 as DONE with the merge timestamp) rather than
retracting either §6 or §7.2.

Edits:
- §15 step 4: annotated "DONE 2026-05-15T00:21:19Z when PR #3077 merged"
  and added the explicit "Step 2 is now genuinely unblocked, not just
  procedurally next" framing so workers reading the sequence don't bypass
  the gate.
- §7.2 line 227: rewritten from "Q7 must ratify before Step 2 brief
  authoring" (future tense, the contradiction surface) to "Gate satisfied
  2026-05-15T00:21:19Z when PR #3077 merged; Step 2 worker brief authoring
  is unblocked at HEAD per §15 step 4." Cites the cursor finding as the
  resolution path.

§6 unblocking statements stay as-is — they were correct at HEAD; the
contradiction lived in §7.2's pre-merge framing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): codex PR #3126 BLOCKING (sha 16d21f4) — Q7 cited at every Step 2 unblocking claim

Codex BLOCKING finding 2 (sha 16d21f4, 216s thinking): the Q7 dependency
was recorded in §7.2/§15 but not in the other Step-2-unblocking sites at
§6 lines 191, 207, 308 — risking a worker reading "Step 2 unblocked" without
also reading the Q7 prerequisite.

Codex framing: "make Q7 a hard precondition wherever Step 2 is called
unblocked, or split Step 2 into pre-Q7 and post-Q7 scopes with separate
receipts."

Chose the first option since PR #3077 has already merged (2026-05-15T00:21:19Z)
and splitting into pre/post-Q7 scopes is no longer load-bearing. Annotated
all three §6 sites:
- Line 191 (Implication for PB-3 migration): cites gate + merge timestamp
  + explicit "must NOT be brief-authored before that merge timestamp."
- Line 207 (Critical observation): cites the Step 2 gate as PR #3077 §12 Q7
  + merge timestamp + P3 failure-shape consequence if violated.
- Line 308 (Director-recommend phase list): cites gate + §7.2/§15 step 4
  cross-refs + merge timestamp.

Codex BLOCKING finding 1 (GrammarSpec carrier non-existence) verified
already resolved at HEAD via commit c97dc15 — every GrammarSpec mention
now explicitly marks it as a concept-not-carrier; Step 2 signature is
`fn parse(tokens: List<Token>) -> Result<SurfaceModule, ParseDiagnostic>`
with no GrammarSpec parameter.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): openai-pro PR #3126 BLOCKING (sha 16d21f4) — Step 3b/4 atomicity + Q1 ratification-pending status

openai-pro REQUEST_CHANGES on PR #3126 sha 16d21f4 flagged three findings.
Findings 1 + 2 (signature vs realization mismatch under LAYER MODEL + P2/P3
boundary discipline) were already resolved at HEAD by earlier fix-forward
commits — Step 2 signature is now `fn parse(tokens: List<Token>) ->
Result<SurfaceModule, ParseDiagnostic>` matching live `parse_generated.rs:138`
with no GrammarSpec parameter and no diagnostics-coupled SurfaceModule
extension (§4.3 Result-sum disposition).

Finding 6 (TRACKED vs UNTRACKED DEBT — Step 3b/4 same-PR vs two-PR):
§9 had both a "Step 3b/4 COMBINED" row (line 250) and a leftover separate
"Step 4: Parity test" row (line 251) — internally contradictory. §15 also
still sequenced Steps 3b + 4 as four separate authoring/dispatch/ratify
beats (steps 12-17), contradicting §12 Q5's "same PR" decision and the
explicit "Update to §15" note at §12 line 325.

Resolution: collapsed §9 to one COMBINED row absorbing the parity-TestClaim
mechanics + P5 dissolution receipt from the deleted Step 4 row; collapsed
§15 steps 12-17 into single COMBINED authoring + dispatch + ratify (steps
12-14). Added explicit `feedback_paper_shrink_variants` reasoning in both
sections.

Finding 2.5 (PM intent — substrate-capability bundled vs separate):
§12 Q1 line 288 said "Director-recommend: (b) bundled" while §13 line 340
listed substrate-capability as a non-goal of PB-3 and §15 step 11 had
"WAIT for substrate-capability landing" — three sections, two different
execution paths.

Resolution: annotated Q1 as "PENDING operator/PM ratification" with
explicit default-execution clause: until operator ratifies, the doc
treats substrate-capability as path (a) separate lane (matching §13 + §15
+ §9 row). If/when ratified to (b), §13 drops the non-goal and §15 step 11
collapses into the COMBINED Step 3b/4 brief.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): codex PR #3126 BLOCKING (sha 5619afa) — parse_tables.dag as single enumerated authority

Codex caught me copying the prose summary at parse_tables.dag:23-29 (which
enumerates only SG-2c-numbered families) instead of grepping the live
`^type [A-Z]` declarations. Result: SoftKeywordIdentRow (line 334) was
missing from §3.2 / §5.1 / §6 / §12 because it lacks an SG-2c-N number
in the prose summary.

Per `feedback_parallel_representation_debt`: structural fix is to stop
hand-enumerating in the doc — cite parse_tables.dag itself as the single
enumerated authority and use `type`-declaration line-anchors for the
worked example, not a hand-maintained count.

Edits:
- §3.2 §"Live substrate authority": replaced the SG-2c-numbered bullet
  list with `type`-declaration line-anchor enumeration including
  SoftKeywordIdentRow at parse_tables.dag:334 + the supporting enum
  BinaryOpLevel at line 133. Added codex-finding callout explaining the
  miss + the discipline shift.
- §3 preamble line:33, §3.2 line:45 callout, §3.2 line:57 framing,
  §3.2 §"Substrate authority" line:71, §5.1 line:171-180, §12 Q2 line:298,
  §12 Q6 line:334: all hardcoded "6 table-families" counts dropped; doc
  now points readers to §3.2 enumeration / `parse_tables.dag` directly.
- §5.1 sub-enumeration list (the parallel 6-item list at lines 173-178)
  deleted; replaced with redirect to §3.2 + restated 3a-vs-3b/4 scope split.

Code-level check before commit: `grep -nE '^type [A-Z]' src/v3/compiler/parse_tables.dag`
returns 7 types: BinaryOpLevel (133), BinaryOpRow (167), TopLevelItemKwRow (289),
SoftKeywordIdentRow (334), BracketRow (385), PrimaryPrefixRow (449),
PrimaryAtomRow (486). Doc enumeration matches.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): codex PR #3138 BLOCKING (sha f08b952) — bind TokenizeDiagnostic to live CharClass authority

Codex Finding 1 (sha f08b952, 216s thinking): the §4.2 TokenizeDiagnostic
draft and the §5.1/§5.2 headings used `ScannerCharClass` / `ScannerClassRef`
— names that exist only as the *generated Rust enum spelling*, not as a
declared .dag substrate type. Verified via grep:

  grep -rn '^type CharClass\|^type ScannerC' dsl/ src/v3/

returns ONE authority: `dsl/std/unicode.dag:62`
  type CharClass = Whitespace | Digit | IdentStart | IdentContinue

consumed at `src/v3/compiler/tokenize.dag:103`
  data ascii_scan_order: List<CharClass> = [Whitespace, Digit, IdentStart, IdentContinue]

There is no `ScannerCharClass` declaration anywhere — that name was copied
from generated Rust without grep-verification, the same failure mode as
`feedback_grep_substrate_before_naming_ratification` (carrier-name
collision discipline).

Resolution:
- §4.2 TokenizeDiagnostic carrier: `expected_class: ScannerClassRef` →
  `expected_class: CharClass`, dropped the `type ScannerClassRef =
  ScannerCharClass` alias entirely; added a codex-finding callout citing
  the substrate authority + naming the failure mode.
- §5.1 heading "Byte → ScannerCharClass dispatch" → "Byte → CharClass
  dispatch"; bullets unchanged; added line-anchor cites for the substrate
  authority + explicit "NOT ScannerCharClass" disclaimer.
- §5.2 heading "ScannerCharClass → token-recognition state machine" →
  "CharClass → token-recognition state machine".

Finding 2 (TokenizedSource not reconciled with parse input contract): no
new fix required — already resolved by commit 6adb992 (TokenizedSource
extension dropped entirely; tokenize uses Result<List<Token>,
TokenizeDiagnostic>; List<Token> is the single canonical boundary carrier
consumed by parse). Codex was reviewing sha f08b952, which predated the
TokenizedSource drop.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3138 INLINE BLOCKING line:188 — clarify §7.3 chain is Ok-branch propagation

Cursor INLINE at sha f08b952 worried that §7.3's cross-stage chain
"tokenize → List<Token> → parse → ..." was inconsistent with §4.3's
TokenizedSource carrier (diagnostics not flowing forward). At HEAD the
TokenizedSource extension is dropped (commit 6adb992); tokenize uses
Result<List<Token>, TokenizeDiagnostic>, so List<Token> IS the canonical
Ok-branch payload that flows forward and Err branches terminate the
pipeline fail-fast.

To make this explicit at §7.3 (instead of leaving readers to infer it
from §4.3), annotated the chain with:
- "Ok-branch propagation; Err branches are stage-terminal fail-fast per
  §4.3 Result-sum discriminator" framing prefix.
- Per-stage Result/typed-state annotations: tokenize/parse show
  Result<Ok, Err>; lower/infer show typed-state structural-output;
  emit shows Result<EmittedArtifact, EmissionDiagnostic>.
- Explicit "on any stage's Err branch the pipeline aborts at that stage
  (no partial-output propagation across boundaries)" trailer.

This makes the chain self-consistent vis-a-vis §4.3 without requiring
the reader to walk back-and-forth, and prevents future readers from
re-introducing a TokenizedSource-shaped extension to "make diagnostics
flow forward" — they already do, just via the Err branch terminating
the pipeline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): openai-pro PR #3127 BLOCKING (sha d15e1f2) — character-level scaffold dissolution trigger

openai-pro REQUEST_CHANGES on sha d15e1f2: §1 line:26 character-level
under-consumption scaffold named the problem but lacked a checkable
dissolution trigger. SG-1a scaffold above had the right shape — "once
those bodies lower structurally under compile_to_dag, delete the raw-text
extractor + derive directly from lowered Dag in same PR." Character-level
scaffold just said "PB-2 Step 4 carries this scope" — a lane assignment,
not a trigger.

Resolution: rewrote §1 item 2 with the same SG-1a-shape trigger structure:
- Substrate-consumption condition (a): scanner classes / string escape /
  local punctuation retype to `dsl/std/unicode.dag` `CharClass` /
  `char_in_class` (concrete field retypes named:
  `StringEscapeSpec.suffix: Char`, `LocalPunctSpec.pattern: List<Char>`,
  `string_literal_delimiter: Char`).
- Codegen-driver condition (b): `tokenize_generated.rs` no longer emits
  hidden `byte.is_ascii_*` predicates because the driver reads class
  facts structurally from lowered `tokenize.dag`.
- Same-PR dissolution: delete the parallel character-predicate scaffold
  in the same PR that flips substrate consumption — no Rust-and-`.dag`
  coexistence per `feedback_paper_shrink_variants`.
- Cross-ref to §9 Step 4 gating prereqs: ROADMAP.md:467 + ROADMAP.md:416
  Class 5 Gap 3 + std.unicode bootstrap/load-set decision (already cited
  in §9 from earlier commit 6adb992).

Per openai-pro's framing: "small fix — mirror the SG-1a scaffold wording
by naming the exact substrate-consumption condition and same-PR deletion
receipt for the hidden Rust character predicates."

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* WIP: gunbc Director

* docs(r3): cursor PR #3127 APPROVE_WITH_COMMENTS — §14 + §15 Q6-already-rejected sweep

Cursor review id 12405 (APPROVE_WITH_COMMENTS) caught the same
`feedback_discipline_change_audit_all_contract_mentions` failure mode
recurring: §12 Q6 was resolved REJECTED in commit 6adb992, and §14
"Surfaces awaiting" + §12 Q6 heading + §9 Step 2 row were updated, but
two §-internal contract restatements were missed:

- §14 acceptance criterion 11: "Operator/PM ratification on §12 Q1-Q6"
- §15 step 1: "Operator / PM-delegate ratifies §12 Q1-Q6"

Both contradicted §12 Q6 + §14 "Surfaces awaiting" (which already said
"Q1-Q5 only"). A worker reading §14/§15 could schedule sign-offs on Q6
after it was already resolved-rejected elsewhere.

Resolution: both sites now say "Q1–Q5" with the explicit Q6-rejected
crossref + "see §14/§15 for same scoping" pointer at the §14 criterion
so the three sections agree internally.

Cursor verdict was APPROVE_WITH_COMMENTS (substantive APPROVE — "fix the
checklist/sequence so every section agrees Q6 is closed"); the
exploratory volatile-line-anchor note is harmless and out-of-scope for
this PR.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): codex PR #3138 BLOCKING (sha 887c696) — 3 findings swept across 3 L2.5 docs

Codex review id (sha 887c696, 333s thinking) flagged three findings,
all `feedback_discipline_change_audit_all_contract_mentions` recurrences
where partial sweeps left §-internal contradictions.

Finding 1 — infer doc cross-stage trigger leak:
§4.2 InferDiagnostic dissolution trigger said "when Step 2 worker brief
enumerates the full variant set against `parse_generated.rs`
Diagnostic::ParseError, lower.rs Diagnostic construction sites, and
infer.rs Dag::mark_unresolved emission sites." That cross-stage trigger
surface is wrong for the infer-specific scaffold. Narrowed to infer-only:
"against `src/v3/compiler/src/infer.rs` Diagnostic construction sites +
`Dag::mark_unresolved` emission sites (infer-stage only)." Parse and lower
have their own per-stage carriers + own Q7 mapping; this doc no longer
reaches into their dissolution-trigger surface.

Finding 2 — parse + tokenize coproduct receipts:
`ParseDiagnosticKind` (parse §4.2) and `TokenizeDiagnostic` (tokenize §4.2)
sums were declared without the 🟡 SCAFFOLD / 🟢 TERMINAL classification +
dissolution trigger that the infer doc carries (per modeling-discipline
Practice 4 + `feedback_coproduct_dissolution`). Added matching scaffold
receipts to both: 🟡 SCAFFOLD at PROPOSED stage with stage-local dissolution
trigger (Step 2 brief enumerates against parse_generated.rs / tokenize_generated.rs
Diagnostic::* construction sites — stage-only, not cross-stage); promote
to 🟢 TERMINAL when full variant set lands. Both also carry the anti-bridge
note per Q6.5.

Finding 3 — tokenize Q7 reconciliation:
The parse doc has the "Q7 DONE 2026-05-15T00:21:19Z" annotation at §15 step 4
(commit f85fa1f) but the tokenize doc still framed Q7 as a pending lane
dependency at §4.2 line:113 ("Lane dependency"), §15 step 3, and §14
"Surfaces awaiting". Annotated all three:
- §4.2 "Lane dependency": Q7 DONE timestamp + "TokenizeDiagnostic per-stage
  variant authoring is the remaining lane work."
- §15 step 3: full DONE annotation matching parse doc §15 step 4 shape +
  cross-ref to the parse doc.
- §14 "Surfaces awaiting": strikethrough + DONE annotation.

PR #3127 also carries the tokenize doc; same edits will port there in a
companion commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3138 INLINE BLOCKING line:372 — §16 Surfaces awaiting Q7 contradiction

Cursor inline at sha 887c696 caught the symmetric finding to the codex
5-finding BLOCKING #3: parse-doc §15 step 4 already annotated Q7 as DONE
(commit f85fa1f) but parse-doc §16 "Surfaces awaiting" still listed Q7
as pending. Same `feedback_discipline_change_audit_all_contract_mentions`
sweep failure — the tokenize doc had three sites carrying the pending
framing (commit e9739ea fixed those) but the parse doc's §16 site was
missed in the original Q7-DONE sweep.

Resolution: §16 bullet now strikes through + "DONE 2026-05-15T00:21:19Z
(PR #3077 merged carrying Q7 ratification; see §15 step 4)" — same shape
as the tokenize doc's §14 "Surfaces awaiting" Q7-DONE annotation landed
in e9739ea.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request May 15, 2026
…+ cursor inlines (#3141)

* docs(r3): PB-2 tokenize pipeline-stage L2.5 domain model — DRAFT for ratification

Director-tier L2.5 model for PB-2 tokenize per operator 2026-05-14
ratification (Decision 1.A scoping = Option A).

PB-2 is the FURTHEST-ALONG pipeline stage — substrate authority
already lives in `.dag`:
- src/v3/std/tokenize.dag (Token + TokenKind taxonomy; LIVE 143
  lines)
- src/v3/compiler/tokenize.dag (tokenizer implementation; LIVE
  154 lines)
- src/v3/compiler/src/tokenize_generated.rs (AUTO-GENERATED; 362
  lines)

This is the END STATE that all other pipeline-stage migrations
target. PB-2 L2.5 is correspondingly lighter — mostly verification
+ residual hand-Rust retirement, NOT new substrate authoring.

Distinct §9 4-step framing:
- Step 3 = VERIFY substrate completeness (audit per
  feedback_paper_shrink_variants)
- Step 4 = HANDOFF/RETIRE residual hand-Rust scaffolding
  (coordinates with PB-Bootstrap-Process lane for codegen-driver
  retirement)

Captures audit dimensions explicitly:
- scanner-class definitions = declarative byte-pattern membership
- recognition tables = closed-axis enums
- state machine = structural transitions
- no V2 `pub mod tokenize` absorption check

§12 Q1: codegen-driver retirement scope — Director-recommend
PB-Bootstrap-Process handles all codegen-driver retirement
cross-cuttingly (not per-stage paper-shrink risk).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): §12.6 citation fix — tokenize is PB-2 lane scope per design-pure-bootstrap-zero.md

Per cursor PR #3085 finding: §12.6 explicitly tables only 4
pipeline-stage migrations (emit→lower→infer→parse); tokenize is
per design-pure-bootstrap-zero.md PB-2 lane. Same fix as PR #3085
commit 89fbd7a2a applied here.

INVARIANTS P1 — documentation must not overstate authority cites.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): preemptive fix for PR #3126 codex BLOCKING propagation — PB-2 live state honesty

Same class as codex INLINE BLOCKING #3126 finding 1 (live state
honesty for diagnostic coupling) applied preemptively to PB-2
tokenize L2.5.

PB-2 §4.3 had "diagnostics coupled INTO List<Token>" framing
which would overstate the live carrier shape (bare List<Token>
has no diagnostic field; tokenize_generated.rs:96 today returns
Result<Vec<Token>, Diagnostic>).

Fix: §4.3 reframed with PROPOSED substrate extension explicit —
new `TokenizedSource { tokens, diagnostics }` wrapper carrier as
the typed-state output. Step 2 brief includes wrapper authoring
in pipeline-slot PR scope.

Same discipline as PR #3126 commit bdff8c500.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3077 — fix PB-2 lane citation (design-pure-bootstrap.md not -zero.md)

Per cursor APPROVE_WITH_COMMENTS /api/reviews/12087: PB-2 lane is
defined in docs/design-pure-bootstrap.md §"PB-2 — tokenize retire"
(line ~134), NOT docs/design-pure-bootstrap-zero.md. The -zero.md
doc has Subsumed-lanes list with PB-1/PB-4/PB-5/PB-6 but NOT PB-2.

Propagated fix applies same cite-error correction as PR #3066 §1.8
discipline: cite the actual doc, not an adjacent doc with similar
name. INVARIANTS P2 single-authority-citation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): fix cursor PR #3127 BLOCKING contradictions + add §12 Q6

Cursor APPROVE_WITH_COMMENTS (/api/reviews/12093) caught two
substantive contradictions I introduced when adding TokenizedSource
in commit 2b9756bb5:

1. §4.3 vs §9 Step 2 signature mismatch — §4.3 said `-> TokenizedSource`
   but §9 Step 2 row still said `-> List<Token>`. Same
   `feedback_discipline_change_audit_all_contract_mentions` issue
   that's recurred 4x this session.

2. §4.3 referenced "§12 Q-new" but §12 only had Q1-Q5; broken anchor.

Fix:
1. §9 Step 2 row updated: signature `-> TokenizedSource` with
   wrapper carrier shape `{ tokens, diagnostics }` per §4.3
2. §4.3 anchor updated: "§12 Q6" (resolved)
3. Added §12 Q6: TokenizedSource carrier shape ratification —
   (a) wrapper record vs (b) per-Token diagnostic coupling;
   Director-recommend (a) for PB-3 SurfaceModule parallelism
4. §14 + §15 + §16 Q-list refs updated to Q1-Q6

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): fix codex BLOCKING PR #3127 — Token shape + Q4 audit boundary

Codex REQUEST_CHANGES (sha b881de23) with 2 substantive findings:

1. §4.1 Token shape claim "optional lexeme: String" — wrong per
   live substrate at src/v3/std/tokenize.dag:65-67. Live Token
   has 2 fields only (kind + span); lexeme-content lives ON the
   TokenKind variants (Ident(String) / IntLit(String) / etc.).

   Fix: corrected §4.1 to reflect live carrier shape; payloads
   on TokenKind variants noted explicitly.

2. §12 Q4 substrate-completeness audit scoped only to
   tokenize_generated.rs — missed the regen_tokenize codegen-
   driver boundary. If regen_tokenize carries scanner-logic
   decisions (rather than mechanical template-rendering of
   substrate facts), the substrate isn't complete — the driver
   IS hand-Rust scanner logic in disguise.

   Fix: Q4 audit extended with (d) regen_tokenize codegen-
   driver logic audit + (e) ROADMAP.md deferral row option per
   feedback_paper_shrink_variants P5 receipt discipline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): fix codex BLOCKING PR #3127 — TokenizeDiagnostic PROPOSED + scaffold disclosure

Codex REQUEST_CHANGES (sha b881de23, full body) caught 2 substantive
overstatements:

1. §2 line 46 claimed "tokenize failures produce typed
   TokenizeDiagnostic variants" — but live tokenize_generated.rs:96
   returns generic `Result<Vec<Token>, Diagnostic>` with
   `Diagnostic::TokenizerError { message, span, correction }`. Typed
   TokenizeDiagnostic is a PROPOSED extension, not live state.

   Fix: §2 reframed with live state explicit + TokenizeDiagnostic
   marked PROPOSED per PR #3077 §12 Q7 ratification path.

2. §1 line 22 + §6 + §9 Step 2 line 198 framed PB-2 as "mostly
   verification" — but live tokenize.dag:16-30+ has TWO explicit
   tracked scaffold zones:
   - SG-1a: regen_tokenize parses raw source text for
     dag_keyword_set / dag_operators (ValueBody::Unparsed)
   - Character-level under-consumption: StringEscapeSpec /
     LocalPunctSpec.pattern / string_literal_delimiter as opaque
     Strings; hidden Rust character predicates (byte.is_ascii_digit
     etc.) at tokenize_generated.rs:15-22 leaking through codegen

   Residual hand-Rust is NOT just the codegen artifact — it includes
   (a) regen_tokenize logic, (b) SG-1a raw-text-extractor scaffold,
   (c) character-predicate scaffold leaking through codegen.

   Fix: §1 + §6 + §9 Step 2 reframed honestly. PB-2 is "FURTHER
   ALONG but not complete"; Step 4 carries scaffold-retirement
   scope, not just codegen-artifact retirement.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): post-merge fix-forward — §16 + §9 Step 2 internal contradictions

Two post-merge doc-internal contradictions caught by reviewers
after operator merged PR #3077 / #3126 / #3085 at 2026-05-15T00:21Z.

**PR #3077 PB-4 lower §16 fix**:
§16 "Memory disciplines applied" bullet said "diagnostics coupled
INTO PreInferDag via biconditional" — but §4.3 (per openai-pro
DiagnosticAnchor fix commit b812db91b) constrains biconditional
to PortAnchor-only. Other anchor kinds (DeclarationAnchor /
RecordFieldAnchor / SurfaceFormAnchor) couple without port-state.
Fix: §16 bullet honors §4.3 anchor-typed framing.

**PR #3126 PB-3 parse §9 Step 2 fix**:
§9 Step 2 row described diagnostics as "coupled INTO SurfaceModule"
as if live — §4.3 correctly marks it PROPOSED. Same
feedback_discipline_change_audit_all_contract_mentions pattern
that's recurred this session.
Fix: §9 Step 2 row clarified — "PROPOSED extension per §4.3";
Step 2 PR scope includes authoring the diagnostics field
extension, NOT a live coupling.

Per feedback_discipline_change_audit_all_contract_mentions: when
a substantive fix changes a discipline framing, audit ALL sections
(framing + contract + handoff). Post-merge audit surfaced these
residual contradictions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): post-merge fix-forward — PR #3126 codex BLOCKING (GrammarSpec parallel-authority + fail-closed weakening)

Codex REQUEST_CHANGES on already-merged PR #3126 (/api/reviews/12175):
2 substantive findings on the post-merge doc.

**Finding 1 (P2 violation — GrammarSpec parallel authority)**:

§3.2 says GrammarSpec is compile-time-only, NOT runtime-
interpreted (per Decision 3.B (b) operator override). But the
proposed stage contract still took `grammar: GrammarSpec` as
runtime input. Creates two authorities (compiled parser tables
+ runtime GrammarSpec value).

Fix: §4.3 signature reframed to `fn parse(tokens: List<Token>)
-> Result<SurfaceModule, ParseDiagnostic>` — NO runtime
GrammarSpec input. Compile-time generated parser tables consumed
via internal dispatch. Step 2 + Step 4 rows updated.

**Finding 2 (P3 + Practices 1/2 — fail-closed weakening)**:

Live parser at parse_generated.rs:138 returns `Result<SurfaceModule,
Diagnostic>` (fail-closed; aborts on first error). Earlier draft
proposed `SurfaceModule` with embedded diagnostics — would let
partial-parse states be constructible + let downstream observe
"success" output after parse failure. Violation of fail-closed
discipline.

Fix: signature preserves Result-sum (matches live + emit's
pattern). Distinguished cross-stage:
- Result-sum (parse + emit): fail-fast output domain
- Typed-state-with-coupled-diagnostics (lower + infer): structural
  output domain where partial-failure IS valid intermediate

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3126 post-merge APPROVE_WITH_COMMENTS — §4.1 + §16 fail-closed honesty

Cursor caught 2 more post-merge contradictions on PR #3126:

1. §4.1 line 81 "construction-time invariant" talks about
   "ParseDiagnostic in the diagnostic stream" tied to SurfaceModule
   path — but §5.2 + live parse_generated.rs:138 use
   Result<SurfaceModule, Diagnostic>. §4.1 reads as claim about
   today's plumbing.

   Fix: §4.1 reframed — live boundary explicit (Result-sum);
   construction-time invariant scoped to Ok-arm SurfaceModule +
   Err-arm ParseDiagnostic, no partial-parse with embedded
   diagnostics.

2. §16 line 397 cites C-8 as "ParseDiagnostic coupled INTO
   SurfaceModule" without qualifier — but §4.3 (post codex
   REQUEST_CHANGES fix) constrains to Result-sum.

   Fix: §16 bullet honors §4.3 Result-sum framing; cross-stage
   discriminator named.

Same recurring feedback_discipline_change_audit_all_contract_mentions
pattern — substantive fix to §4.3 + §9 Step 2 left §4.1 + §16
inconsistent. Post-merge audit catches.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3085 INLINE BLOCKING — TypeConnective extension stop-signal

Cursor INLINE BLOCKING caught §3.2 line 66 "rules extend
automatically" weakens substrate-extension stop-signal. Thesis
discipline: a 7th TypeConnective variant requires explicit C1
audit + named infer-rule receipt.

Fix: §3.2 reframed. New TypeConnective variants do NOT extend
automatically; require explicit C1 substrate-extension audit +
named infer-rule receipt for the new variant's structural
inference behavior.

Per-variant structural facts means new variants need new
per-variant facts, NOT silent inheritance.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3085 INLINE BLOCKING — AlgebraAxis + InferDiagnostic Practice 4 classification

Cursor INLINE BLOCKING /api/reviews/12218 (line:112): proposed
substrate coproducts (AlgebraAxis + InferDiagnostic) lack
🟢/🟡/🔴 classification + ledger/trigger per modeling-discipline
Practice 4 (Coproduct dissolution).

Fix: added 🟡 SCAFFOLD classification + named dissolution
trigger for both:

AlgebraAxis 🟡 SCAFFOLD:
- Trigger: Step 2 brief enumerates full algebra-axiom set
  against infer.rs check sites + verifies coverage parity
  with live verification.dag:146 AlgebraicLawKind 3-variant
  subset → promote to 🟢 TERMINAL.

InferDiagnostic 🟡 SCAFFOLD:
- Trigger: Step 2 brief enumerates full variant set against
  parse_generated.rs / lower.rs / infer.rs diagnostic emission
  sites → promote to 🟢 TERMINAL.
- Anti-bridge per Q6.5: does NOT collapse into
  CompilerDiagnosticKind without substrate-extension
  ratification per PR #3077 §12 Q7.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3077 INLINE BLOCKING — §5.1 SurfaceItem allocation correction

Cursor INLINE BLOCKING /api/reviews/12251 line:130: §5.1 said
"every SurfaceItem variant maps 1:1 to a Declaration placeholder"
but live lower.rs:2950-2958 explicitly skips Let/Module/Import
in collect_symbols.

Verified via Read of lower.rs:2956-2958:
  SurfaceItem::Let { .. } => continue,
  SurfaceItem::Module { .. } => continue,
  SurfaceItem::Import { .. } => continue,

Fix: §5.1 reframed — DeclarationAllocating variants (Fn /
FnExternalBody / Data / TypeAtom / TypeRecord) map to
placeholders; NonDeclarationAllocating variants (Let / Module /
Import) skip allocation per live lower.rs behavior.

Let-bodies lower to Bind expressions in Pass 2; Module/Import
are parsed-facts preserved but un-declared.

Earlier "every SurfaceItem variant" framing overstated; would
have steered Step 2/3 worker into wrong allocation contract.
Per INVARIANTS P1/P2 live-state honesty + facts-flow-forward.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3077 INLINE BLOCKING — ElaborationSpec scope broadened

Cursor INLINE BLOCKING line:33: ElaborationSpec was defined only
as Surface→Behavior recipe mapping, but lower constructs
Declarations / TypeConnectives / BranchPatterns / Bindings as
well. Non-Behavior lowering decisions outside declared authority
violates THESIS substrate ownership + INVARIANTS P2.

Fix: §3.2 ElaborationSpec scope broadened to ALL lowering
decisions:

1. SurfaceItem → Declaration recipes (Fn / Data / Type variants +
   Let/Module/Import skip-allocation per §5.1)
2. SurfaceType → TypeConnective recipes (Atom / Arrow / Compose /
   Disj construction)
3. SurfaceExpr → Behavior recipes (Value / Transform / Branch /
   Loop / Bind construction)
4. SurfacePattern → BranchPattern recipes (ResolvedVariant /
   UnresolvedVariant / record-pattern construction)
5. Binding-site rules (Bind params + result_port construction)

ElaborationSpec is single-authority across ALL axes; no axis
lives in implementation-tier hand-Rust.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3126 APPROVE_WITH_COMMENTS — §7.1 ordering vs independence clarification

Cursor APPROVE_WITH_COMMENTS /api/reviews/12265 line 197: §7.1
mixed two claims:
- "parse migrates AFTER tokenize substrate-side stable" (ordering)
- "PB-3 parse migration is independent of PB-2 tokenize migration
  status" (independence)

Read as contradictory by reviewers. Need one coherent story.

Fix: §7.1 reframed with two distinct axes explicit:

1. Substrate-stability ordering (SELF_HOSTING.md §2 bottom-up):
   tokenize Token carrier shape must be stable BEFORE parse
   migrates. Already true at HEAD (tokenize.dag:65-67 declares
   live carrier). ✓

2. Migration-timing independence (parallel-dispatch axis): PB-3
   parse migration ships in parallel with PB-2 residual-retirement
   work (SG-1a + character-level scaffold + codegen-driver
   retirement per PB-2 L2.5 §1). What parse needs is the stable
   Token CARRIER; PB-2's migration is about retiring residual
   hand-Rust, not changing the carrier.

Both claims coherent on the axis split; not contradictory.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3126 INLINE BLOCKING — ParseDiagnostic SourceSpan structural requirement

Cursor INLINE BLOCKING /api/reviews/12277 line:65: ParseDiagnostic
variants like UnexpectedToken lacked SourceSpan field;
List<ParseDiagnostic> cannot satisfy fail-closed source
attribution structurally without span on every variant.
INVARIANTS P2/P3 violation.

Fix: every ParseDiagnostic variant now carries SourceSpan
structurally:
- UnexpectedToken: added span: SourceSpan
- UnterminatedConstruct: opener_span: SourceSpan (already present)
- InvalidLiteral: added span: SourceSpan
- DuplicateRecordFieldLabel: added span: SourceSpan (current site)
  + prior_span: SourceSpan (prior site; both required)

Per INVARIANTS P2/P3 fail-closed source attribution discipline:
every diagnostic emission carries structural source-span
provenance; not optional.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3126 INLINE BLOCKING — Token authority cite phantom-reference fix

Cursor INLINE BLOCKING /api/reviews/12279 line:29: §3.1 cited
`src/v3/compiler/src/tokenize.rs` as "current hand-Rust" for
Token carrier — but `tokenize.rs` (without _generated suffix)
doesn't exist. Live state has tokenize.dag (live substrate) +
tokenize_generated.rs (codegen artifact).

Per design-pure-bootstrap.md PB-2 lane: tokenize retire has
substantially landed. The reference was an earlier-draft
phantom from when Token-was-hand-Rust framing was the assumption.

Fix: §3.1 reframed — Token type lives in LIVE
src/v3/std/tokenize.dag:65-67 shared taxonomy; tokenizer
implementation also live at src/v3/compiler/tokenize.dag (154
lines); codegen artifact at tokenize_generated.rs. tokenize.rs
phantom reference removed explicitly. PB-2 substantially landed
per design-pure-bootstrap.md; residual scaffold-retirement
scope per PB-2 L2.5 PR #3127.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3126 INLINE BLOCKING — Step 2 pipeline-slot target fix (compiler.dag → pipeline.dag)

Cursor INLINE BLOCKING /api/reviews/12281 line:138: §9 Step 2
referenced generic "compiler.dag" but dsl/gunbc/compiler.dag:24
explicitly directs internal pipeline (Tokenize → Parse → ...)
to src/v3/compiler/pipeline.dag, NOT generic compiler.dag.

Worker briefs authored against this doc would target the wrong
file for pipeline-slot declaration. P2 single-authority violation.

Fix: §9 Step 2 row in ALL 4 L2.5 docs (PB-2 / PB-3 / PB-4 / PB-5)
updated:
- "declared in compiler.dag" → "declared in src/v3/compiler/pipeline.dag (per dsl/gunbc/compiler.dag:24 — internal pipeline lives in pipeline.dag, NOT generic compiler.dag)"
- substrate column: "compiler.dag refinement" → "pipeline.dag refinement"
- §13 "Step 2 (pipeline-slot in compiler.dag)" → "pipeline-slot in src/v3/compiler/pipeline.dag"

Same phantom-citation class as the tokenize.rs phantom (commit
8ae37b4a5): I cited generic file path without verifying which
specific file is authoritative per project structure. Should
have grep'd dsl/gunbc/compiler.dag header notes before authoring.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3126 INLINE BLOCKING — Step 3b/4 phasing P5 receipt unambiguity

Cursor INLINE BLOCKING /api/reviews/12283 line:181: Q5 said
Step 3b "full parser body .dag migration + parser body deletion
in same PR", but §15 sequence schedules Step 4 parity/deletion
AFTER Step 3b merges. P5 dissolution receipt ambiguous.

If Step 3b lands .dag parser body BEFORE Step 4 deletes Rust
parse() body, Rust + .dag parser bodies coexist temporarily —
paper-shrink-relocation risk per feedback_paper_shrink_variants.

Fix:
1. §9 Step 3b row reframed as "Step 3b/4 COMBINED" — atomic
   single PR (full .dag parser body + parity TestClaim +
   parse_generated.rs:138 deletion + census shrink). Cannot land
   .dag parser body before Rust deletion.
2. §12 Q5 phasing clarified:
   - Phase 3a (separate PR): grammar table extension; P5 receipt
     = ROADMAP deferral row naming Step 3b/4 as future-receipt
   - Phase 3b/4 COMBINED (single PR): atomic substrate substitution
3. §9 + §15 update notes: sequence collapses steps 12-17 into
   single dispatch+merge for combined phase

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): codex PR #3126 high-level BLOCKING findings 1 + 2

Codex high-level BLOCKING (sha 140eb6bb) had 4 findings:
- Findings 3 + 4 already addressed in PR #3138 commits 015977347
  + a1607a88d
- Findings 1 + 2 addressed in this commit

**Finding 1 (Diagnostic kind/record conflated)**:
§4.2 ParseDiagnostic was modeled as variants-directly with span
+ kind-fields mixed. Live Diagnostic at diagnostics.dag:150 uses
record-wraps-kind pattern (`{ kind, span, message, correction }`).
Need consistent shape.

Fix: refactored to record-wraps-kind:
- `type ParseDiagnostic { kind: ParseDiagnosticKind, span: SourceSpan }`
- `type ParseDiagnosticKind = UnexpectedToken | UnterminatedConstruct | InvalidLiteral | DuplicateRecordFieldLabel | ...`

Span lives on ParseDiagnostic record (single source of truth);
variant-specific spans (opener_span / prior_span) remain on kind
variants where meaningful.

**Finding 2 (PB-2 §6 obsolete sibling-lane assumption)**:
§6 line 198 said "PB-2 Tokenize | src/v3/std/tokenize.dag (NEW
per PB-2 L2.5)" — but tokenize.dag is ALREADY LIVE per
design-pure-bootstrap.md §"PB-2 — tokenize retire" (substantially
landed).

Fix: §6 prereq table row updated to reflect LIVE state. PB-2's
residual scope is scaffold-retirement (SG-1a + character-level +
codegen-driver per PB-2 L2.5 §1), not carrier authoring. PB-3
consumes the live Token carrier; carrier shape stable across
PB-2 residual-retirement timing.

Findings 3 + 4 already addressed:
- Finding 3 (pipeline.dag target): commit 015977347
- Finding 4 (Step 3b/4 atomic vs sequential): commit a1607a88d

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3126 APPROVE_WITH_COMMENTS — phantom "module-level metadata" removed

Cursor APPROVE_WITH_COMMENTS line:79: §4.1 said "SurfaceModule
(verified live) carries List<SurfaceItem> + module-level
metadata" — but live parse_surface.dag:29 has ONLY
`{ items: List<SurfaceItem> }`. No metadata fields.

Phantom addition violated INVARIANTS P1 live-state honesty.

Fix: §4.1 reframed to match live carrier exactly. Same
phantom-addition class as tokenize.rs phantom (commit 8ae37b4a5).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): codex PR #3085 high-level BLOCKING findings — AtomPayload 5-variant + diagnostic-table PROPOSED

Codex high-level BLOCKING (sha bf4d3152) — 2 substantive findings:

**Finding 1 (AtomPayload stale)**:
§2 + §5 cited infer.rs:10 top-comment "Atom(Identifier { name,
resolved })" — but live substrate.dag:87 has 5-variant
AtomPayload sum: Literal | UnresolvedIdentifier |
ResolvedByStructure | ResolvedByName | TypeParam.

infer.rs top-comment is STALE vs live substrate. My doc inherited
the drift.

Fix: §2 enumeration corrected to all 5 AtomPayload variants per
live substrate.dag:87.

**Finding 2 (diagnostic-table PROPOSED, not live)**:
§2 + §4.1 + §4.3 said "diagnostics.contains(port_id)
biconditional" as if live — but Dag at substrate.dag:525 has
ONLY { declarations, nodes, ports, clusters }. NO diagnostics
field. Diagnostic-table is PROPOSED substrate extension.

Fix: §2 fail-closed note flagged PROPOSED — Step 2 PR scope
includes `diagnostics: Map<PortId, Diagnostic>` field extension
to Dag, OR PB-Substrate prereq adds it before PB-5 dispatch.

Same recurring feedback_grep_carrier_field_before_coupling_claim
discipline (PR #3126 SurfaceModule analogous case); needed to
grep type Dag fields BEFORE claiming the diagnostics field
exists.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3085 INLINE BLOCKING line:94 — §4.1 + §4.3 PROPOSED diagnostic-table marking

Cursor INLINE BLOCKING line:94: §4.1 + §4.3 said "diagnostics
coupled INTO InferredDag" without flagging the diagnostic-table
as a substrate extension. Live Dag at substrate.dag:525 has
{ declarations, nodes, ports, clusters } — NO diagnostics field.
Earlier commit c0d96af25 added PROPOSED marking only in §2;
§4.1 + §4.3 needed same treatment.

Fix: §4.1 + §4.3 reframed with explicit PROPOSED substrate-
extension marking + reference to §2 for extension scope.
Construction-time invariant + structural coupling are both
contingent on the substrate-extension landing (Step 2 PR scope
or PB-Substrate prereq).

Same recurring feedback_grep_carrier_field_before_coupling_claim
discipline applied to §4.1 + §4.3 consistently with §2.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): codex PR #3077 high-level BLOCKING — Practice 4 classifications for PB-4 coproducts

Codex high-level BLOCKING (sha b812db91): "Diagnostic substrate
shape was repaired around anchoring but not re-audited as new
substrate type declarations" — meaning DiagnosticAnchor +
LowerDiagnostic + SurfaceFormRef + IdentifierRef need
🟢/🟡/🔴 classifications per modeling-discipline Practice 4
(Coproduct dissolution).

Same pattern as PB-5 fix in commit 040681f21 (AlgebraAxis +
InferDiagnostic) applied here.

Fix: added classifications + dissolution triggers:

- SurfaceFormRef 🟢 TERMINAL: closed-axis sum over live Surface*
  carriers; no further dissolution.
- IdentifierRef 🟡 SCAFFOLD: dissolution trigger = Step 2 brief
  enumerates full identifier-kind set against lower.rs
  identifier-resolution sites; promote to 🟢 TERMINAL when
  SurfaceVarRef + TypePathRef + ModulePathRef cover actual axes.
- LowerDiagnostic 🟡 SCAFFOLD: dissolution trigger = Step 2 brief
  enumerates variant set against lower.rs Diagnostic emission
  sites + Q6.5 anti-bridge preserved + PR #3077 §12 Q7
  ratification path.
- DiagnosticAnchor 🟢 TERMINAL: closed-axis covering all
  lowering-stage anchor kinds; no further dissolution.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3077 INLINE BLOCKING line:161 — DiagnosticSource Practice 4 classification

Cursor inline finding adds DiagnosticSource to Practice 4
classification scope. Earlier commit aba79a142 classified
SurfaceFormRef + IdentifierRef + LowerDiagnostic + DiagnosticAnchor
but missed DiagnosticSource.

Fix: DiagnosticSource 🟢 TERMINAL at pipeline-stage
discrimination scope. Closed-axis sum (Parse | Lower | Infer |
Emit); adding new pipeline stage requires explicit substrate-
extension audit per Practice 4 + stop-signal discipline (same
shape as PB-5 §3.2 TypeConnective stop-signal).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3126 INLINE BLOCKING line:151 — §11 SurfaceItem::Let + SurfaceLiteral span correction

Cursor INLINE BLOCKING line:151: §11 claimed "every Surface
variant carries SourceSpan" but live parse_surface.dag has:
- SurfaceItem::Let { name, type_ann, expr } — no direct span
- SurfaceLiteral = Int(String) | Bool(Bool) | String(String) —
  plain-tuple variants with no direct span

Source-span provenance for these cases is via enclosing carrier:
SurfaceLiteral wraps within `Literal { value, span }` at
parse_surface.dag:150. Let-item inherits container span.

INVARIANTS P2/P3 source provenance is structurally guaranteed
via direct-OR-enclosing carrier, but my "every variant"
overstatement obscured this.

Fix: §11 corrected to "most Surface variants carry SourceSpan
directly" + explicit Let + SurfaceLiteral exceptions noted +
Step 2 PR scope audits whether exceptions are structural-honest
(enclosing-carrier-provides-span) OR require substrate extension.

Same recurring overstatement class as earlier "every SurfaceItem
maps 1:1 to Declaration" (commit 61e2b67cd) — need to grep live
substrate variant fields BEFORE claiming uniform shape.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* WIP: gunbc Director

* docs(r3): cursor PR #3126 INLINE BLOCKING line:32 — GrammarSpec is concept, not carrier

Earlier draft (now-merged PR #3126) framed `GrammarSpec` as a second declared
`.dag` input type alongside `List<Token>`. Verified via grep that no
`type GrammarSpec` exists anywhere under src/v3/ or dsl/ — the repo carries
only `parse_tables.dag`'s 6 SG-2c table-families. Per cursor 2026-05-14T23:30:04Z
inline finding, this violates INVARIANTS P2 (the Step-2 signature names a
carrier the substrate doesn't declare).

Reframed §3 (and downstream mentions in §3.2, §3 preamble line:33, §4.2
codex-correction recap line:165, §5.1 line:181, §12 Q6 line:344) so that:

- Parse has ONE input at the API boundary: `List<Token>`.
- "GrammarSpec" is a concept-level grouping for the 6 compile-time table-families
  in `parse_tables.dag`, not a substrate carrier and not a runtime parameter.
- Step-2 signature stays `fn parse(tokens: List<Token>) -> Result<SurfaceModule, ParseDiagnostic>`
  per cfe842b2d (already applied in #3126); these edits remove the lingering
  "two input types" framing that contradicted that signature.

Per Decision 3.B (b) compile-time parser tables: substrate authority is
parse_tables.dag (6 table-families) consumed via direct table lookups inside
the parser body — no runtime grammar value, no `GrammarSpec` carrier needed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): codex PR #3138 BLOCKING — §4.3 + §16 internal contradictions resolved

Codex review id 12391 on sha cd6e8d15 flagged two live statements of the
already-rejected typed-state-with-coupled-diagnostics model still sitting
inside the parse L2.5, contradicting the corrected Result-sum framing in §4.2
and §6 Step 2:

1. §4.3 still proposed a `SurfaceModule { items, diagnostics }` extension
   modeled on PB-4/PB-5 patterns. Reframed: §4.3 now states explicitly that
   parse-stage uses Result-sum (no diagnostics field on SurfaceModule),
   restates the cross-stage discriminator (Result-sum for fail-fast output
   domains: parse + emit; typed-state for structural output domains: lower +
   infer), and cites `parse_generated.rs:138` as the live shape.

2. §16 "Memory disciplines applied" bullet read
   "feedback_state_space_vs_behavioral_invariants (typed-state SurfaceModule
   at output)". Rewritten to "parse output is `Result<SurfaceModule,
   ParseDiagnostic>` — the type rules out partial-parse states by
   construction; SurfaceModule itself carries no diagnostic field per §4.3".

Per `feedback_discipline_change_audit_all_contract_mentions`: when a
contract changes (here: SurfaceModule extension dropped in favor of
Result-sum), all §-internal restatements must be swept in the same diff
or they leak through as authoritative parallel claims.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): codex PR #3127 BLOCKING — drop TokenizedSource extension + cite concrete P5 receipts

Codex review id 12370 on sha d15e1f29 raised two load-bearing planning-shape
findings on the tokenize L2.5. Addressed in this fix-forward branch (PR #3138)
since PR #3127 is still open but accumulating cycles.

Finding 1 — parallel boundary carriers (INVARIANTS P2 / Modeling Practices 3+5):
§4.3 + §9 Step 2 + §12 Q6 named `TokenizedSource { tokens, diagnostics }` as the
output, while §2/§7.2/§7.3 named `List<Token>`. Same misclassification I just
removed from the parse L2.5 in PR #3138 §4.3: tokenize sits in the fail-fast
output domain alongside PB-3 parse + PB-6 emit (a partial token list with a
corrupt token in the middle is not a valid downstream input for parse), so the
failure couples via `Result`, not into the structural carrier.

Resolution:
- §4.3 rewritten to ratify `Result<List<Token>, TokenizeDiagnostic>` — the live
  `tokenize_generated.rs:96` shape — with no `TokenizedSource` extension.
- §9 Step 2 row signature updated to match; explicit "single canonical boundary
  carrier: List<Token> on the Ok branch" framing.
- §12 Q6 resolved REJECTED in-doc (no operator ratification needed; disposition
  follows from the cross-stage discriminator that's also load-bearing in PR
  #3138 parse L2.5).
- §16 memory-disciplines bullets rewritten parallel to PR #3138 parse §16:
  Result-sum, no diagnostics field on `List<Token>`.
- §14 "Surfaces awaiting" trimmed Q6 from the operator-ratification list.

Finding 2 — soft deferral of `regen_tokenize` retirement (INVARIANTS P5):
deferral previously named "PB-Bootstrap-Process lane scope" without a concrete
ROADMAP.md row. Updated §9 Step 2 + Step 4 rows to cite the named receipts:
- `docs/design-pure-bootstrap-zero.md:116` (PB-Bootstrap-Process lane: author
  bootstrap.dag + generated trampoline; sized M).
- `docs/design-pure-bootstrap-zero.md:118-123` (N=0 runtime verification gates).
- ROADMAP.md:467 (Character-level under-consumption in tokenize + syntax
  authorities — phase-2 char-class retype owns the codegen-driver path).
- ROADMAP.md:416 (Class 5 Gap 3 — top-level `ValueBody` boundary; gating
  substrate-capability for the phase-2 retype).
- ROADMAP.md:53 (T-PB-A — non-test census → 0 floor).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3126 BLOCKING line:119 — §6/§7.2/§15 Q7 sequencing resolved by PR #3077 merge

Cursor inline BLOCKING at docs/design-parse-stage-l25-model.md:119 (sha at
merge time of PR #3126) flagged a real internal contradiction:
- §6 (lines 191, 207, 308) claimed "Step 2 (pipeline-slot declaration) is
  unblocked"
- §7.2 (line 227) claimed "PR #3077 §12 Q7 must ratify before any Step 2
  worker brief authoring"

A worker reading the doc could land Step 2 (pipeline boundary) before the
diagnostic carrier's P2/P3 failure shape was fixed.

Resolution: PR #3077 (PB-4 lower L2.5) merged at 2026-05-15T00:21:19Z,
carrying the §12 Q7 ratification of the Decision 2.B per-stage diagnostic
extension path. The gate IS now satisfied at HEAD, so the resolution is
fact-update (annotate Q7 as DONE with the merge timestamp) rather than
retracting either §6 or §7.2.

Edits:
- §15 step 4: annotated "DONE 2026-05-15T00:21:19Z when PR #3077 merged"
  and added the explicit "Step 2 is now genuinely unblocked, not just
  procedurally next" framing so workers reading the sequence don't bypass
  the gate.
- §7.2 line 227: rewritten from "Q7 must ratify before Step 2 brief
  authoring" (future tense, the contradiction surface) to "Gate satisfied
  2026-05-15T00:21:19Z when PR #3077 merged; Step 2 worker brief authoring
  is unblocked at HEAD per §15 step 4." Cites the cursor finding as the
  resolution path.

§6 unblocking statements stay as-is — they were correct at HEAD; the
contradiction lived in §7.2's pre-merge framing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): codex PR #3126 BLOCKING (sha 16d21f4a) — Q7 cited at every Step 2 unblocking claim

Codex BLOCKING finding 2 (sha 16d21f4a, 216s thinking): the Q7 dependency
was recorded in §7.2/§15 but not in the other Step-2-unblocking sites at
§6 lines 191, 207, 308 — risking a worker reading "Step 2 unblocked" without
also reading the Q7 prerequisite.

Codex framing: "make Q7 a hard precondition wherever Step 2 is called
unblocked, or split Step 2 into pre-Q7 and post-Q7 scopes with separate
receipts."

Chose the first option since PR #3077 has already merged (2026-05-15T00:21:19Z)
and splitting into pre/post-Q7 scopes is no longer load-bearing. Annotated
all three §6 sites:
- Line 191 (Implication for PB-3 migration): cites gate + merge timestamp
  + explicit "must NOT be brief-authored before that merge timestamp."
- Line 207 (Critical observation): cites the Step 2 gate as PR #3077 §12 Q7
  + merge timestamp + P3 failure-shape consequence if violated.
- Line 308 (Director-recommend phase list): cites gate + §7.2/§15 step 4
  cross-refs + merge timestamp.

Codex BLOCKING finding 1 (GrammarSpec carrier non-existence) verified
already resolved at HEAD via commit c97dc15ae — every GrammarSpec mention
now explicitly marks it as a concept-not-carrier; Step 2 signature is
`fn parse(tokens: List<Token>) -> Result<SurfaceModule, ParseDiagnostic>`
with no GrammarSpec parameter.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): openai-pro PR #3126 BLOCKING (sha 16d21f4a) — Step 3b/4 atomicity + Q1 ratification-pending status

openai-pro REQUEST_CHANGES on PR #3126 sha 16d21f4a flagged three findings.
Findings 1 + 2 (signature vs realization mismatch under LAYER MODEL + P2/P3
boundary discipline) were already resolved at HEAD by earlier fix-forward
commits — Step 2 signature is now `fn parse(tokens: List<Token>) ->
Result<SurfaceModule, ParseDiagnostic>` matching live `parse_generated.rs:138`
with no GrammarSpec parameter and no diagnostics-coupled SurfaceModule
extension (§4.3 Result-sum disposition).

Finding 6 (TRACKED vs UNTRACKED DEBT — Step 3b/4 same-PR vs two-PR):
§9 had both a "Step 3b/4 COMBINED" row (line 250) and a leftover separate
"Step 4: Parity test" row (line 251) — internally contradictory. §15 also
still sequenced Steps 3b + 4 as four separate authoring/dispatch/ratify
beats (steps 12-17), contradicting §12 Q5's "same PR" decision and the
explicit "Update to §15" note at §12 line 325.

Resolution: collapsed §9 to one COMBINED row absorbing the parity-TestClaim
mechanics + P5 dissolution receipt from the deleted Step 4 row; collapsed
§15 steps 12-17 into single COMBINED authoring + dispatch + ratify (steps
12-14). Added explicit `feedback_paper_shrink_variants` reasoning in both
sections.

Finding 2.5 (PM intent — substrate-capability bundled vs separate):
§12 Q1 line 288 said "Director-recommend: (b) bundled" while §13 line 340
listed substrate-capability as a non-goal of PB-3 and §15 step 11 had
"WAIT for substrate-capability landing" — three sections, two different
execution paths.

Resolution: annotated Q1 as "PENDING operator/PM ratification" with
explicit default-execution clause: until operator ratifies, the doc
treats substrate-capability as path (a) separate lane (matching §13 + §15
+ §9 row). If/when ratified to (b), §13 drops the non-goal and §15 step 11
collapses into the COMBINED Step 3b/4 brief.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): codex PR #3126 BLOCKING (sha 5619afac) — parse_tables.dag as single enumerated authority

Codex caught me copying the prose summary at parse_tables.dag:23-29 (which
enumerates only SG-2c-numbered families) instead of grepping the live
`^type [A-Z]` declarations. Result: SoftKeywordIdentRow (line 334) was
missing from §3.2 / §5.1 / §6 / §12 because it lacks an SG-2c-N number
in the prose summary.

Per `feedback_parallel_representation_debt`: structural fix is to stop
hand-enumerating in the doc — cite parse_tables.dag itself as the single
enumerated authority and use `type`-declaration line-anchors for the
worked example, not a hand-maintained count.

Edits:
- §3.2 §"Live substrate authority": replaced the SG-2c-numbered bullet
  list with `type`-declaration line-anchor enumeration including
  SoftKeywordIdentRow at parse_tables.dag:334 + the supporting enum
  BinaryOpLevel at line 133. Added codex-finding callout explaining the
  miss + the discipline shift.
- §3 preamble line:33, §3.2 line:45 callout, §3.2 line:57 framing,
  §3.2 §"Substrate authority" line:71, §5.1 line:171-180, §12 Q2 line:298,
  §12 Q6 line:334: all hardcoded "6 table-families" counts dropped; doc
  now points readers to §3.2 enumeration / `parse_tables.dag` directly.
- §5.1 sub-enumeration list (the parallel 6-item list at lines 173-178)
  deleted; replaced with redirect to §3.2 + restated 3a-vs-3b/4 scope split.

Code-level check before commit: `grep -nE '^type [A-Z]' src/v3/compiler/parse_tables.dag`
returns 7 types: BinaryOpLevel (133), BinaryOpRow (167), TopLevelItemKwRow (289),
SoftKeywordIdentRow (334), BracketRow (385), PrimaryPrefixRow (449),
PrimaryAtomRow (486). Doc enumeration matches.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): codex PR #3138 BLOCKING (sha f08b9525) — bind TokenizeDiagnostic to live CharClass authority

Codex Finding 1 (sha f08b9525, 216s thinking): the §4.2 TokenizeDiagnostic
draft and the §5.1/§5.2 headings used `ScannerCharClass` / `ScannerClassRef`
— names that exist only as the *generated Rust enum spelling*, not as a
declared .dag substrate type. Verified via grep:

  grep -rn '^type CharClass\|^type ScannerC' dsl/ src/v3/

returns ONE authority: `dsl/std/unicode.dag:62`
  type CharClass = Whitespace | Digit | IdentStart | IdentContinue

consumed at `src/v3/compiler/tokenize.dag:103`
  data ascii_scan_order: List<CharClass> = [Whitespace, Digit, IdentStart, IdentContinue]

There is no `ScannerCharClass` declaration anywhere — that name was copied
from generated Rust without grep-verification, the same failure mode as
`feedback_grep_substrate_before_naming_ratification` (carrier-name
collision discipline).

Resolution:
- §4.2 TokenizeDiagnostic carrier: `expected_class: ScannerClassRef` →
  `expected_class: CharClass`, dropped the `type ScannerClassRef =
  ScannerCharClass` alias entirely; added a codex-finding callout citing
  the substrate authority + naming the failure mode.
- §5.1 heading "Byte → ScannerCharClass dispatch" → "Byte → CharClass
  dispatch"; bullets unchanged; added line-anchor cites for the substrate
  authority + explicit "NOT ScannerCharClass" disclaimer.
- §5.2 heading "ScannerCharClass → token-recognition state machine" →
  "CharClass → token-recognition state machine".

Finding 2 (TokenizedSource not reconciled with parse input contract): no
new fix required — already resolved by commit 6adb99227 (TokenizedSource
extension dropped entirely; tokenize uses Result<List<Token>,
TokenizeDiagnostic>; List<Token> is the single canonical boundary carrier
consumed by parse). Codex was reviewing sha f08b9525, which predated the
TokenizedSource drop.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3138 INLINE BLOCKING line:188 — clarify §7.3 chain is Ok-branch propagation

Cursor INLINE at sha f08b9525 worried that §7.3's cross-stage chain
"tokenize → List<Token> → parse → ..." was inconsistent with §4.3's
TokenizedSource carrier (diagnostics not flowing forward). At HEAD the
TokenizedSource extension is dropped (commit 6adb99227); tokenize uses
Result<List<Token>, TokenizeDiagnostic>, so List<Token> IS the canonical
Ok-branch payload that flows forward and Err branches terminate the
pipeline fail-fast.

To make this explicit at §7.3 (instead of leaving readers to infer it
from §4.3), annotated the chain with:
- "Ok-branch propagation; Err branches are stage-terminal fail-fast per
  §4.3 Result-sum discriminator" framing prefix.
- Per-stage Result/typed-state annotations: tokenize/parse show
  Result<Ok, Err>; lower/infer show typed-state structural-output;
  emit shows Result<EmittedArtifact, EmissionDiagnostic>.
- Explicit "on any stage's Err branch the pipeline aborts at that stage
  (no partial-output propagation across boundaries)" trailer.

This makes the chain self-consistent vis-a-vis §4.3 without requiring
the reader to walk back-and-forth, and prevents future readers from
re-introducing a TokenizedSource-shaped extension to "make diagnostics
flow forward" — they already do, just via the Err branch terminating
the pipeline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): openai-pro PR #3127 BLOCKING (sha d15e1f29) — character-level scaffold dissolution trigger

openai-pro REQUEST_CHANGES on sha d15e1f29: §1 line:26 character-level
under-consumption scaffold named the problem but lacked a checkable
dissolution trigger. SG-1a scaffold above had the right shape — "once
those bodies lower structurally under compile_to_dag, delete the raw-text
extractor + derive directly from lowered Dag in same PR." Character-level
scaffold just said "PB-2 Step 4 carries this scope" — a lane assignment,
not a trigger.

Resolution: rewrote §1 item 2 with the same SG-1a-shape trigger structure:
- Substrate-consumption condition (a): scanner classes / string escape /
  local punctuation retype to `dsl/std/unicode.dag` `CharClass` /
  `char_in_class` (concrete field retypes named:
  `StringEscapeSpec.suffix: Char`, `LocalPunctSpec.pattern: List<Char>`,
  `string_literal_delimiter: Char`).
- Codegen-driver condition (b): `tokenize_generated.rs` no longer emits
  hidden `byte.is_ascii_*` predicates because the driver reads class
  facts structurally from lowered `tokenize.dag`.
- Same-PR dissolution: delete the parallel character-predicate scaffold
  in the same PR that flips substrate consumption — no Rust-and-`.dag`
  coexistence per `feedback_paper_shrink_variants`.
- Cross-ref to §9 Step 4 gating prereqs: ROADMAP.md:467 + ROADMAP.md:416
  Class 5 Gap 3 + std.unicode bootstrap/load-set decision (already cited
  in §9 from earlier commit 6adb99227).

Per openai-pro's framing: "small fix — mirror the SG-1a scaffold wording
by naming the exact substrate-consumption condition and same-PR deletion
receipt for the hidden Rust character predicates."

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* WIP: gunbc Director

* docs(r3): cursor PR #3127 APPROVE_WITH_COMMENTS — §14 + §15 Q6-already-rejected sweep

Cursor review id 12405 (APPROVE_WITH_COMMENTS) caught the same
`feedback_discipline_change_audit_all_contract_mentions` failure mode
recurring: §12 Q6 was resolved REJECTED in commit 6adb99227, and §14
"Surfaces awaiting" + §12 Q6 heading + §9 Step 2 row were updated, but
two §-internal contract restatements were missed:

- §14 acceptance criterion 11: "Operator/PM ratification on §12 Q1-Q6"
- §15 step 1: "Operator / PM-delegate ratifies §12 Q1-Q6"

Both contradicted §12 Q6 + §14 "Surfaces awaiting" (which already said
"Q1-Q5 only"). A worker reading §14/§15 could schedule sign-offs on Q6
after it was already resolved-rejected elsewhere.

Resolution: both sites now say "Q1–Q5" with the explicit Q6-rejected
crossref + "see §14/§15 for same scoping" pointer at the §14 criterion
so the three sections agree internally.

Cursor verdict was APPROVE_WITH_COMMENTS (substantive APPROVE — "fix the
checklist/sequence so every section agrees Q6 is closed"); the
exploratory volatile-line-anchor note is harmless and out-of-scope for
this PR.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): codex PR #3138 BLOCKING (sha 887c69671) — 3 findings swept across 3 L2.5 docs

Codex review id (sha 887c69671, 333s thinking) flagged three findings,
all `feedback_discipline_change_audit_all_contract_mentions` recurrences
where partial sweeps left §-internal contradictions.

Finding 1 — infer doc cross-stage trigger leak:
§4.2 InferDiagnostic dissolution trigger said "when Step 2 worker brief
enumerates the full variant set against `parse_generated.rs`
Diagnostic::ParseError, lower.rs Diagnostic construction sites, and
infer.rs Dag::mark_unresolved emission sites." That cross-stage trigger
surface is wrong for the infer-specific scaffold. Narrowed to infer-only:
"against `src/v3/compiler/src/infer.rs` Diagnostic construction sites +
`Dag::mark_unresolved` emission sites (infer-stage only)." Parse and lower
have their own per-stage carriers + own Q7 mapping; this doc no longer
reaches into their dissolution-trigger surface.

Finding 2 — parse + tokenize coproduct receipts:
`ParseDiagnosticKind` (parse §4.2) and `TokenizeDiagnostic` (tokenize §4.2)
sums were declared without the 🟡 SCAFFOLD / 🟢 TERMINAL classification +
dissolution trigger that the infer doc carries (per modeling-discipline
Practice 4 + `feedback_coproduct_dissolution`). Added matching scaffold
receipts to both: 🟡 SCAFFOLD at PROPOSED stage with stage-local dissolution
trigger (Step 2 brief enumerates against parse_generated.rs / tokenize_generated.rs
Diagnostic::* construction sites — stage-only, not cross-stage); promote
to 🟢 TERMINAL when full variant set lands. Both also carry the anti-bridge
note per Q6.5.

Finding 3 — tokenize Q7 reconciliation:
The parse doc has the "Q7 DONE 2026-05-15T00:21:19Z" annotation at §15 step 4
(commit f85fa1f6b) but the tokenize doc still framed Q7 as a pending lane
dependency at §4.2 line:113 ("Lane dependency"), §15 step 3, and §14
"Surfaces awaiting". Annotated all three:
- §4.2 "Lane dependency": Q7 DONE timestamp + "TokenizeDiagnostic per-stage
  variant authoring is the remaining lane work."
- §15 step 3: full DONE annotation matching parse doc §15 step 4 shape +
  cross-ref to the parse doc.
- §14 "Surfaces awaiting": strikethrough + DONE annotation.

PR #3127 also carries the tokenize doc; same edits will port there in a
companion commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3138 INLINE BLOCKING line:372 — §16 Surfaces awaiting Q7 contradiction

Cursor inline at sha 887c69671 caught the symmetric finding to the codex
5-finding BLOCKING #3: parse-doc §15 step 4 already annotated Q7 as DONE
(commit f85fa1f6b) but parse-doc §16 "Surfaces awaiting" still listed Q7
as pending. Same `feedback_discipline_change_audit_all_contract_mentions`
sweep failure — the tokenize doc had three sites carrying the pending
framing (commit e9739ea4f fixed those) but the parse doc's §16 site was
missed in the original Q7-DONE sweep.

Resolution: §16 bullet now strikes through + "DONE 2026-05-15T00:21:19Z
(PR #3077 merged carrying Q7 ratification; see §15 step 4)" — same shape
as the tokenize doc's §14 "Surfaces awaiting" Q7-DONE annotation landed
in e9739ea4f.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): codex PR #3127 BLOCKING (sha 8e682eef) — §3.1 source identity + §4.2 live-vs-proposed clarity

PR #3127 was merged at 02:04:22Z but codex's later review on sha 8e682eef
caught two findings that still live in main. Both addressed in this PR
(PR #3140) since the tokenize doc lives on main and this is the open
post-merge cleanup branch.

Finding 1 — §3.1 source-identity drop:
Earlier draft framed tokenize input as bare `String → List<Token>`. That
contradicts live `tokenize_generated.rs:96`:
  pub fn tokenize(source: &str, file: &str) -> Result<Vec<Token>, Diagnostic>
The `file` parameter is load-bearing because `SourceSpan` requires a
file/source-id field for byte ranges to be attributable; without it the
Token + Diagnostic span fields would have to fabricate source-id at the
pipeline boundary (P3 fail-closed violation). §3.1 now ratifies the live
two-input shape:
- `source: String` — UTF-8 source text (primitive).
- `file: SourceFileId` — source-identity carrier; Step 2 brief ratifies
  the appropriate `.dag` shape (NonEmptyStr newtype or richer sum if
  multiple source-class kinds).

Finding 2 — §4.2 live-vs-proposed blur:
Prior framing said "TokenizeDiagnostic (substrate extension per Decision
2.B)" without making clear that this is a PROPOSED per-stage carrier,
not the live one. The live carrier at `diagnostics.dag:150` is generic
`Diagnostic { kind: AnyDiagnosticKind, ... }` with kind sum at `:139-142`
discriminating CompilerKind vs LensInstanceKind; tokenize emits today
via `Diagnostic::TokenizerError`-shaped sites carrying
`kind: CompilerKind(...)`. §4.2 heading now reads "PROPOSED — NOT yet
live" + a codex-finding callout explicitly distinguishing the live
carrier from the proposed per-stage refinement + Q7 status DONE.

Both fixes preserve the e9739ea4f 🟡 SCAFFOLD coproduct receipt that
was already addressing codex sha 887c69671 Finding 2.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3127 INLINE BLOCKING line:121 — §4.3 + §9 Step 2 signature sweep

Cursor inline at sha 8e682eef line:121 (the §4.3 Step 2 signature site)
caught the same source-identity drop my §3.1 fix already addressed at the
input-type framing — but two companion sites still had the single-input
signature:
- §4.3 line:151 Step 2 signature recap
- §9 Step 2 row (4-step migration table)

Both now read:
  fn tokenize(source: String, file: SourceFileId) -> Result<List<Token>, TokenizeDiagnostic>

matching the §3.1 source-identity discipline + live `tokenize_generated.rs:96`
`pub fn tokenize(source: &str, file: &str)` shape.

Same `feedback_discipline_change_audit_all_contract_mentions` recurrence
— my Finding 1 fix at §3.1 (commit 18af49fad) didn't sweep the §4.3 + §9
contract-signature restatements.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3127 INLINE BLOCKING line:166 — §6 row TokenizeDiagnostic LIVE/PROPOSED clarity

Cursor inline caught ambiguity in the §6 prereq-table row for
"TokenizeDiagnostic substrate extension." Old wording in column 4 read
"Carrier LIVE; per-stage variant authoring NEW" which could be parsed
as "TokenizeDiagnostic carrier itself is LIVE" — but no `type
TokenizeDiagnostic` exists in `dsl/std/` or `src/v3/std/`. Only the
generic `type Diagnostic` at `diagnostics.dag:150` is live.

Cursor's secondary claim that "line 150 is EmissionDiagnostic receipt
prose" is INCORRECT — verified via grep + read: `diagnostics.dag:150`
is the `type Diagnostic { kind: AnyDiagnosticKind, ... }` declaration
header. `type EmissionDiagnostic` lives separately at `diagnostics.dag:201`.
The §6 row's citation of `:150` for the underlying Diagnostic carrier
is correct.

But the ambiguity-in-wording finding stands. Reframed the row:
- Column 1: explicitly "PROPOSED — no `type TokenizeDiagnostic` exists yet"
- Column 2: clarifies the LIVE underlying carrier is `type Diagnostic`
  with `kind: AnyDiagnosticKind` sum at `:139-142`; cites Q7 ratification
  done timestamp.
- Column 4: explicit "Underlying Diagnostic carrier LIVE at HEAD;
  per-stage TokenizeDiagnostic variant authoring is NEW work, NOT live
  substrate" with cursor-finding callout.

Consistent with §4.2's "PROPOSED — NOT yet live" framing from commit
18af49fad.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3141 INLINE BLOCKING line:68 — §2 structural-signature sweep

Cursor inline caught §2 still framing tokenize structural signature as
`String → List<Token>` — single bare-string input, no source-identity,
no Result-sum failure shape — while §3.1 + §4.3 + §9 Step 2 row all
ratify the live two-input + fail-fast Result-sum shape.

Same `feedback_discipline_change_audit_all_contract_mentions` recurrence
that's been compounding across this fix-forward sequence: each finding
fix needs a doc-wide signature-restatement sweep, not just the §-local
sentence.

Resolution: §2 structural-shape sentence now reads
  `(String, SourceFileId) → Result<List<Token>, TokenizeDiagnostic>`
matching §3.1 (source-identity), §4.3 (Result-sum cross-stage
discriminator), §9 Step 2 row, and live `tokenize_generated.rs:96`
`pub fn tokenize(source: &str, file: &str) -> Result<Vec<Token>,
Diagnostic>`. Cross-refs added to §3.1 + §4.3 to make the discipline
visible at the high-level framing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3141 INLINE BLOCKING line:73 — replace invented SourceFileId with live FilePath

Cursor caught me inventing `SourceFileId` as the Step 2 boundary type
without a live `.dag` declaration. Verified via grep:
  grep -rn '^type SourceFileId' dsl/ src/v3/
returns empty. Same `feedback_grep_substrate_before_naming_ratification`
family error as the earlier `ScannerCharClass` miss — naming a substrate
carrier without grep-verification.

Live carrier already exists at `dsl/std/types.dag:276`:
  type FilePath = String where non_empty

referenced by `type SourceSpan { file: FilePath, ... }` at
`dsl/std/types.dag:293`. So source identity flows through every Token +
Diagnostic span field via the live `FilePath` carrier — no new carrier
authoring needed at Step 2.

Edits:
- §2 structural-signature: `(String, SourceFileId)` → `(String, FilePath)`
- §3.1 source-identity bullet: replaces fictional SourceFileId with the
  live `FilePath` declaration cite (dsl/std/types.dag:276), points out
  that `SourceSpan.file` already references this same carrier, and adds
  a cursor-finding callout naming the failure mode.
- §4.3 + §9 Step 2 signature restatements: `file: SourceFileId` →
  `file: FilePath`.

Single substrate authority (INVARIANTS P1/P2) restored: FilePath is the
one carrier for source identity across SourceSpan + tokenize input +
Token construction.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request May 15, 2026
…afts) (#3139)

* docs(r3): rust retirement catalogue + emit.rs modeling doc (format-validation drafts)

Per operator 2026-05-15 directive — replace SG-0 file-path ratchet (which
rewards file-path manipulation / paper-shrink) with a substrate-authority
planning artifact. Focus on actual `.dag` substrate growth, not ratchet
file-list shrinkage.

Two docs:

(1) `docs/r3-rust-retirement-catalogue.md` (159 lines)
- Framing: explicit anti-paper-shrink stance citing
  `feedback_template_relocation_paper_shrink_discriminator` (cycles 4/5/6
  reverts at PR #3059)
- Format spec for per-entry catalogue: Role / Public surface / Inputs /
  Calls into / Called by / Existing `.dag` substrate / Retirement target /
  Replacement plan (R1=substrate, R2=consumer-reads-substrate-not-template,
  R3=parity invariant — semantic NOT textual) / Anti-paper-shrink check /
  Phase 1-5 / Substantive retirement risks
- 5-phase retirement plan ordered cheapest-first:
  Phase 1: hand-Rust monotonicity invariant (foreclose growth)
  Phase 2: test harness layer (122 → 1-3 via .dag TestClaim)
  Phase 3: lens-as-Rust (7-10 → 0 via data lens_X: Lens<C> + fold_lens)
  Phase 4: substrate-mirror generation (5-8 → 0 via regen reads
           substrate.dag)
  Phase 5: pipeline-stage retirement (12-15 → meta-circular bootstrap)
- One worked example entry: src/v3/compiler/src/emit.rs (3,992 lines)
  with 4 substantive retirement risks flagged
- 5 open format questions for operator before scaling to remaining ~176
  entries

(2) `docs/r3-retirement-modeling-emit-rs.md` (310 lines)
- Per-file modeling doc; first instance of a series (one per Rust file)
- §1 What emit.rs does (4 internal layers identified)
- §2 Reference pattern (tokenize.dag) — the proven `.dag`-drives-retirement
  example
- §3 6-layer identification ordered by tractability (Layer 1 dispatcher =
  most tractable; Layer 6 = whole-file retirement)
- §4 Layer 1 (dispatcher) FULLY MODELED:
  * 4 new substrate carriers in src/v3/std/emit_model.dag: EmitTarget,
    EmitMode, EmittedSource, EmitTargetDispatchRow
  * 1 data value: emit_target_dispatch_table
  * 3 pure functions: emit_with_mode, emit, emit_module
  * Codegen driver outline: new regen_emit_dispatcher.rs following
    regen_tokenize.rs pattern
  * Parity verification: SEMANTIC (m1_3/m1_4 integration tests pass
    unchanged) NOT TEXTUAL (no source-clone)
- §5 Sketches for Layers 2-N
- §6 4 open questions about .dag substrate-language features needed
- §7 Substantive retirement risks (paper-shrink discriminators)
- §8 What Layer 1 demonstrates (proof-of-pattern for emit translation)

Neither doc proposes changing the ratchet now — that's separate operator
direction. These are planning artifacts for the substantive retirement
work, not enforcement bridges.

Tokenize/parse pipeline stages are already fully substrate-driven (the
proof-of-concept). Lower/infer/emit have L2.5 design docs (PR #3066,
#3077, #3085, #3126 just merged) but no executable `.dag` substrate yet —
the modeling doc series identifies the smallest tractable layer per file
to begin substantive migration.

Co-authored-by: Brian (operator briansrls) — directive 2026-05-15

* docs(r3-catalogue): restructure per claude APPROVE-exploratory PR #3139 — move 5-phase plan above format spec (single authority for Phase enum)

claude APPROVE on commit 458b08d (PR #3139, 2026-05-15T02:14:43Z) flagged a
non-blocking exploratory note: "the catalogue's Phase enum is defined inside
the per-entry format spec block, but the 5-phase plan section at the bottom
is the canonical authority — if this doc lives long, consider moving the
phase definitions above the format spec so the format references rather than
redefines them."

Applied — the doc now has the 5-phase plan section FIRST, with full
definitions, and the format spec section references Phase numbers without
duplicating definitions. Eliminates the dual-authority problem the
exploratory note identified.

Section order (post-fix):
- §"5-phase plan (canonical authority for Phase enum referenced below)"
- §"Format spec (per entry — references Phase numbers from §"5-phase plan"
  above)"
- §"Catalogue" (worked example: emit.rs)
- §"(Remaining ~176 entries — to be filled per format-ratified spec)"
- §"Open questions for operator before format is ratified"

The format spec's Phase field now reads: "Phase: one of Phase 1–5 per
§"5-phase plan" above. (Definitions are NOT duplicated here — the §"5-phase
plan" section is the single authority.)"

No content changes beyond structure; doc is 154 lines (down 5 from
de-duplication of the Phase definitions).

* docs(r3): add Path B tokenize/parse brief set (9 briefs, no workarounds)

Per operator directive 2026-05-15 — "could we try to do path B for tokenize/
parse (NO workarounds) now — i'd like to spawn workers under you directly".

Planning doc enumerating the 9 briefs needed for true 100% .dag retirement
of tokenize + parse including codegen drivers. Workers spawn directly under
deep-wolf-155 (PM) per operator; no Director/Mgr layer for this lane.

Dispatch graph:
- Phase 0 (parallel, no deps): Briefs 1-3 substrate-language gaps
  - Brief 1: generic methods on FreeMonoid<T> (non-endomorphic map + per-method type params; named gap at dsl/std/algebra.dag:387-393)
  - Brief 2: format(template, args) + Int/Char/Bool → String primitives
  - Brief 3: char-class structural completion (finish in-progress scaffold at tokenize.dag:23-58)
- Phase 1 (parallel, no deps on Phase 0): Briefs 4-6 host effects + bridge
  - Brief 4: FileReadEffect + FileWriteEffect (bundle)
  - Brief 5: ProcessSpawnEffect (for rustfmt)
  - Brief 6: compile_to_dag FFI bridge — operator decision point (FFI vs self-hosted)
- Phase 2 (depends on Phases 0+1): Briefs 7-9 driver authoring
  - Brief 7: tokenize_codegen.dag (retires regen_tokenize.rs 1,186 lines)
  - Brief 8: parse_tables_codegen.dag (retires regen_parse_tables_emit.rs 1,284 lines)
  - Brief 9: parse_codegen.dag (retires regen_parse_emit.rs 124 lines)

Cumulative: 6-12 months optimistic, 12-18 realistic. Substrate-language work
in Briefs 1-6 unblocks Phase 2/3/5 broader retirement paths beyond
tokenize/parse alone.

5 open questions for operator at end of doc:
1. Brief 6 FFI vs self-hosted architectural choice
2. Spawn cadence (parallel vs sequential)
3. Test harness scope (in or out of this brief set)
4. Substrate-language work attribution to Phase 2/3/5
5. Worker parallelism cap (3-4 in flight realistic)

Anti-paper-shrink discriminator applies to all 9 briefs: substrate-growth
PR-by-PR is the receipt, not file-path shrinkage.

* docs(briefs): add Path B Phase 0 worker briefs (1-3) — individual files for dispatched workers

Workers witty-moth-725 (Brief 1), sunny-tern-495 (Brief 2), bright-swift-668
(Brief 3) auto-spawned under deep-wolf-155 per operator directive. The work-
item titles were truncated and didn't carry full brief content; this commit
provides the canonical single-file brief per worker.

- docs/briefs/r3-path-b-brief-1-freemonoid-generic-methods.md
  Worker: witty-moth-725
  Gap: dsl/std/algebra.dag:387-393 (FreeMonoid<T>.map endomorphic only)
  Estimated effort: 2-6 months substrate-language work

- docs/briefs/r3-path-b-brief-2-string-templating-conversions.md
  Worker: sunny-tern-495
  Gap: no format(template, args) + verify Int/Char/Bool → String primitives
  Estimated effort: 1-3 months

- docs/briefs/r3-path-b-brief-3-char-class-structural.md
  Worker: bright-swift-668
  Gap: tokenize.dag:23-58 named scaffold (char_in_class NYI for structural execution)
  Estimated effort: 1-2 months

Each brief:
- Investigation-first (Phase A) — surface findings to deep-wolf-155 before authoring
- Concrete deliverables + acceptance criteria (substrate-fact-at-HEAD)
- Anti-paper-shrink discriminator (substrate growth, not file-path manipulation)
- Coordination protocol: direct dashboard-message to deep-wolf-155, no Director/Mgr layer
- PR title prefix r3-path-b-brief-N for traceability

* docs(r3): address codex + briansrls BLOCKING PR #3139 — align catalogue with 0-floor target + dissolve EmitTarget closed enum into LanguageSpec open registry

Two valid BLOCKING findings:

(1) codex REQUEST_CHANGES (catalogue.md:31, :52, :55) — "irreducible 10-15
    file seed" + "Irreducible bootstrap seed (cannot retire)" framings
    CONTRADICTED `docs/design-pure-bootstrap-zero.md` (LIVE 2026-04-25
    cascade promotion) which establishes the in-tree floor as ZERO.
    Authoritative text:
    - line 41: "Goal: zero hand-authored files in v3's source tree."
    - line 95: "the in-tree floor target is 0 regardless of which N=0
      resolution lands"
    - line 191: "If first-time bootstrap (N=0) resolution requires
      hand-Rust in v3's source tree — STOP. The resolution is supposed
      to live outside v3's source tree (install script, gunbc-runtime
      crate, or rustc macro)."

(2) briansrls INLINE BLOCKING (modeling-emit-rs.md:125) — proposed
    `type EmitTarget = Go | Rust | Python` closed sum REINTRODUCED a
    target roster that the live `src/v3/std/emit_model.dag` header
    (lines 8-16) explicitly dissolves via LanguageSpec references:
    "Adding a new shared target is a pure spec-file change — drop a
    `<target>.dag` with a LanguageSpec data item and reference it from
    each realization. No compiler enum roster to edit."

Fixes:

Catalogue (docs/r3-rust-retirement-catalogue.md):
- §"5-phase plan" end-state: replaced "irreducible 10-15 file seed"
  with 0-floor target. Files that look irreducible (bootstrap drivers
  etc.) retire by MOVING OUT-OF-TREE per design-pure-bootstrap-zero.md
  N=0 resolution paths (install script / gunbc-runtime crate / rustc
  macro), NOT by accepting a permanent in-tree residual.
- §"Format spec" per-entry "Retirement target" options: replaced
  "Irreducible bootstrap seed (cannot retire; document why)" with
  "Moved out-of-tree". Added explicit (N.B.) citing codex BLOCKING +
  design-pure-bootstrap-zero.md line 191: planning artifact does NOT
  have authority to introduce permanent in-tree carve-outs against the
  live 0-floor design.

Modeling doc (docs/r3-retirement-modeling-emit-rs.md):
- §4.1 substrate carriers: retracted `type EmitTarget = Go | Rust |
  Python` closed sum. Replaced `EmittedSource.target: EmitTarget` with
  `EmittedSource.language: DeclarationRef` matching the
  `TypeRealization.language: DeclarationRef` pattern at
  emit_model.dag:18. Removed `EmitTargetDispatchRow` separate roster
  carrier — LanguageSpec registry IS the roster.
- §4.2/§4.3: dispatch reads LanguageSpec declarations from
  src/v3/spec/*.dag directly via declaration-namespace walk; functions
  now take `language: DeclarationRef` parameter.
- §4.4 codegen driver: GENERATED Rust uses open-registry pattern too —
  no hardcoded `match EmitTarget { Go => ..., Rust => ..., Python => ... }`
  in emitted code; dispatches via DeclarationId lookup against the
  live LanguageSpec registry.
- §6 open question #2: variant-arm exhaustiveness check replaced with
  declaration-namespace-walk-by-type-tag (open-registry concern).
- §7 substantive retirement risks: paper-shrink discriminator updated
  (no closed enum reintroduction in generated Rust). Cross-target
  convenience wrappers collapse to ONE `emit_text(dag, language)`
  parameterized function.

EmitMode = Program | Module stays as a closed sum (intentionally
bounded; structurally distinct from target-roster concern).

* docs(r3): address briansrls BLOCKING PR #3139 at catalogue.md:21 — expand Phase 1 monotonicity invariant to full hand-Rust surface (include src/v3/compiler/tests/**)

briansrls inline BLOCKING at 2026-05-15T02:48:45Z flagged that Phase 1
scoped only src/v3/compiler/src/, leaving Rust tests outside the
net-shrink gate even though INVARIANTS.md P5 + T-PB-B explicitly
include Rust tests in the hand-Rust surface.

Verified at INVARIANTS.md:323 (Dispatch-Discipline Mechanisms (b)):
  "Hand-Rust includes Rust tests (src/v3/compiler/tests/**) — these
   are the T-PB-B test subset of the SG-0 census; the gate applies
   the same way it applies to T-PB-A non-test files."

Fix: Phase 1 monotonicity invariant now scopes the FULL hand-Rust
surface (src + tests). Eliminates the loophole where gate-closure
PRs adding Rust tests would skirt the invariant — which is exactly
the growth pattern observed in the SG-0 trajectory data (TEST array
went 122 → 130 → 131 across recent gate-closure PRs).

* docs(r3): M2 / class-5 deferral debt survey (operator-requested 2026-05-15)

Per operator directive: "Can we please find all instances of this happening
in this project - i want to attack one of these problems specifically so we
can gather some confidence."

Survey enumerates the M2-deferred / class-5-blocked work in the project:

Quantitative scope:
- 119 references to "class-5" across docs/ + src/v3/ + dsl/
- 61 citations naming class-5 as a blocker / dissolution trigger
- 161 ArrowBody::Unparsed std fn bodies (58% of 276 total)
- 1 dedicated design doc (docs/design-m2-feature-parity.md, status "Design
  ready for implementer review") sitting unimplemented

Enumeration:
1. M2 Feature Parity (DB-9 through DB-13, design doc ready):
   - DB-9: Mutual recursion lowering (L)
   - DB-10: data value semantics (S) — RECOMMENDED ATTACK POINT
   - DB-11: where refinement predicates (M)
   - DB-12: surface generics (S)
   - DB-13: Disj dotted-path (S)
2. Class-5 grammar gaps (substrate-language sub-program):
   - #1: Brace-bodied fn on .dag files (161 Unparsed std fns)
   - #2: Record literals inside data bodies
   - #3: Lens-fold prereq
   - #4: Variant-constructor expressions
   - #5: Dimension<C> data declarations (blocked on #2)
   - #6: Name rosters
3. Hand-Rust trampolines that exist BECAUSE class-5 isn't closed
4. Downstream symptoms (R3 retirement stalls, lens trampolines, etc.)

Recommendation: DB-10 (data value semantics) as confidence-builder:
- Smallest (size S per doc)
- Substrate carrier already exists (Declaration.value_body at dag.rs:122)
- Gap is downstream consumers, not substrate-shape change
- Closes class-5 sub-gap #2 + unblocks dimension framework + cost-lens
  trampoline retirement
- Estimated 1-2 weeks if design is accurate
- Demonstrates "we can close M2 deferrals" pattern

Alternative: class-5 brace-body parse for .dag files (bigger lever, more
invasive; coordinates with Brief 3 worker bright-swift-668).

* docs(r3-catalogue): clean up stale 'irreducible bootstrap seed' reference in Open Questions §5 (briansrls BLOCKING PR #3139 follow-through at catalogue.md:163)

briansrls BLOCKING at catalogue.md:31 about the "irreducible 10-15 file
seed" framing was already addressed in commit 6bafd12 (relay arrived
after fix per dashboard typical relay-after-fix pattern). However, a
stale reference to "irreducible bootstrap seed" remained at line 163
in the Open Questions section — reframed as "move out-of-tree per
design-pure-bootstrap-zero.md N=0 resolution paths" with explicit
no-permanent-residual disclaimer.

The retraction at lines 31-38 + §"Format spec" (N.B.) at line 64
remains the canonical retraction text per the prior commit.

* docs(briefs): add Path B Brief 4 — DB-10 data value semantics (M2/class-5 confidence-builder attack point)

Per operator directive 2026-05-15 — "lets attack DB-10 for confidence,
give it to one of the existing path B brief members".

Brief 4 dispatches DB-10 (data value semantics, M2 feature parity item 3a.2)
to witty-moth-725 — they closed Brief 1 cleanly (PR #3142 promoted to
ready) and are available for new substrate-language work.

Authoritative design at docs/design-m2-feature-parity.md §DB-10 (lines
20-71); doc carries "Design ready for implementer review" status since
authoring. This is the FIRST attack against the M2 / class-5 deferral
pit per the survey at docs/r3-m2-class-5-deferral-survey.md.

Scope:
- Phase A: verify design-doc cited locations (dag.rs:122, lower.rs:1404,
  test_3a2_data_field_access_resolves_statically test ratchet) against
  HEAD; surface drift findings to deep-wolf-155
- Phase B: land 3 consumers per design — Dag::data_value_at accessor +
  SurfaceExpr::Var fallback for scalar inlining + lower_field_path_expr
  walks ValueBody::Structural for static field access
- Phase C: test fixture demonstrating data answer = 42 + answer + 1
  emits 42 + 1 inline across all 3 target languages

Architectural commitment honored (per design + PR #496 2026-04-17):
inlining at LOWERING, not emission. Load-bearing per locked test ratchet.
Emission-time inlining REJECTED.

Coordination: parallel to PR #3142 merge (Brief 1 closure); separate
branch; report findings directly to deep-wolf-155 (no Director/Mgr
layer). Coordinate with sunny-tern-495 (Brief 2) + bright-swift-668
(Brief 3) only if substrate work overlaps.

Anti-paper-shrink discriminator: locked test asserts no FieldProject
Transform exists in the lowered DAG for data-resolved field accesses;
that ratchet catches trampoline-style workarounds.

Estimated effort: 1-2 weeks if design doc is accurate.

* docs(r3): retract stale 'M2 not landed' framing — DB-10/12/13 verified LANDED at HEAD 2026-05-15

Per gentle-bat-24 Brief 4 Phase A finding (DB-10 substrate already
implemented at HEAD with `Dag::data_value_at` at dag.rs:4310 +
lower.rs:8489+/8642+/9125+ + passing test at m2_feature_parity_test.rs:771)
+ subsequent verification of DB-12/DB-13 status amendments in PR #496 against
HEAD test names:

DB-10: LANDED
DB-12: LANDED (parse_generated.rs:927; m2_feature_parity_test.rs:90-156)
DB-13: LANDED (lower.rs:3375; m2_feature_parity_test.rs:163-208)
DB-9 + DB-11: HEAD landed-state NOT YET AUDITED; may also be silently landed

Sites updated:
- docs/r3-m2-class-5-deferral-survey.md: M2 feature parity table reframed
  with cited HEAD evidence per DB; explicit retraction of "no DB item has
  landed yet" claim; active deferral pits shrink to DB-9 + DB-11 (pending
  audit) plus class-5 sub-gaps which remain genuinely deferred per Brief 3
  findings
- docs/design-m2-feature-parity.md: top-level Status line updated from
  "Design ready for implementer review" to "3 of 4 LANDED" with per-DB
  cited HEAD evidence; explicit advisory that workers should audit HEAD
  state before authoring implementation against this doc

Residual M2 work for the 3 LANDED items: emission-test-coverage gap for
DB-12 + DB-13 (design §Acceptance promises 3-target render verification;
current tests check compile + lower only). Small follow-up scope; not
pit-shaped.

The "M2 deferral pit" framing was substantially wrong as initially
described — much of M2 has been silently landing. The class-5 sub-gaps
remain genuinely deferred per Brief 3's bright-swift-668 investigation
(brace-body fn parse on .dag files).

Per `feedback_corrections_must_grep_verify_source` — this is the
canonical lesson: design docs drift; verify against HEAD before
authoring against them.

* docs(r3): address codex BLOCKING PR #3139 (review #12458) — retract String-typed EmitDispatchError + retract Brief 6 FFI bridge as deliverable path

Two findings, both valid:

(1) modeling-emit-rs.md:203 — proposed `type EmitDispatchError { language:
DeclarationRef, detail: String }` as 🟡 SCAFFOLD. RETRACTED. INVARIANTS P3 +
docs/modeling-discipline.md Practice 1 forbid String-typed diagnostic channels
at the substrate-API level. SCAFFOLD-with-String at the API level is still
a String-API at HEAD; the scaffold marker doesn't excuse the typed-carrier
requirement.

Fix: defer the EmitDispatchError shape entirely until per-language typed error
carriers land (Brief 7+). Dispatcher signature stays Result<EmittedSource, ???>
with ??? as forward-reference. Workers attempting Brief 7+ surface back if
the error-carrier shape becomes load-bearing before per-language errors exist
— substantive substrate-language question, not papered over with String channel.

(2) brief-set.md:206 — Brief 6 presented an "FFI bridge" option (a) as a
deliverable path. The brief text itself admitted "does not retire the Rust
compile_to_dag function itself" — that's a bridge preserving hand-Rust
compiler authority, NOT retirement. Operator's NO WORKAROUNDS stance +
INVARIANTS P5 forbid FFI as deliverable path. The brief currently muddled
this; codex correctly flagged that the wording would send a worker to execute
the wrong work.

Fix: Brief 6 reframed as SCOPE MARKER ONLY (Phase 5 program, NOT dispatchable
within this brief set). Recommendation surfaced to operator: declare Phase 5
/ meta-circular bootstrap as separate program from Path B; tokenize/parse
codegen-driver retirements (Briefs 7-9) are downstream of Phase 5 and not
landable until self-hosted compile_to_dag lands. Honest framing: forcing
Briefs 7-9 to land before Phase 5 via FFI bridges produces paper-shrink, not
retirement.

Sites updated:
- modeling-emit-rs.md §4.3 EmitDispatchError block: explicit RETRACTION text;
  signature now Result<EmittedSource, ???> with forward-reference framing
- brief-set.md §"Brief 6 — Meta-circular: compile_to_dag Foreign-Function Bridge"
  retitled to "self-hosted compile_to_dag (Phase 5 scope expansion)" + scope
  reframed as SCOPE MARKER ONLY
- brief-set.md dispatch graph: Brief 6 marked NOT DISPATCHABLE
- brief-set.md §Brief 7 prerequisites: Briefs 1-5 + Phase 5 separately
- brief-set.md §Brief 7 scope: cites separately-scoped Phase 5 program
- brief-set.md §"Open questions for operator before dispatch" #1: RESOLVED
  per this codex BLOCKING; no FFI workaround acceptable

* WIP: Path B Brief 4 — M2 DB-10 data value semantics (data foo: T = v usable a

* docs(r3): finish typed emit error retraction
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant