Skip to content

docs(r3): PB-4 lower pipeline-stage L2.5 domain model — DRAFT for ratification - #3077

Merged
briansrls merged 20 commits into
mainfrom
docs/director-pb4-lower-l25-model
May 15, 2026
Merged

briansrls merged 20 commits into
mainfrom
docs/director-pb4-lower-l25-model

Conversation

@briansrls

Copy link
Copy Markdown
Contributor

Summary

  • Director-tier L2.5 domain model for PB-4 lower pipeline stage per operator 2026-05-14 ratification:
    • Decision 1.A scoping = Option A (pipeline-stage L2.5s = Director scope)
    • "have pm sign off on everything" delegation for remaining 11 technical decisions
  • 388 lines / 16 sections. DRAFT status awaiting operator/PM ratification of §12 Q1–Q6 open design questions.
  • Unblocks PB-4 lane execution authority dispatch via R3 Substrate Mgr (warm-wolf-698) once §12 ratified.

Context

Per SELF_HOSTING.md §2.2 gating rule 4: PB-4 lower-stage L3 .dag substrate work cannot start until this L2.5 is reviewed. PB-6 emit L2.5 landed at PR #3066; PB-4 lower is next in migration order (per substrate-reflection-design.md §12.6 bottom-up: emit → lower → infer → parse → tokenize).

Authoring discipline applied

This doc applies all learnings from the PR #3066 PB-6 emit L2.5 BLOCKING-review cycle:

  • Grep-verified ALL substrate citations BEFORE authoring (not after BLOCKINGs)
  • Typed-state carrier from start — output is PreInferDag variant per Decision 3.A operator-ratified sum-variant shape
  • Practice 4 (Coproduct dissolution) + Practice 2 (illegal states unrepresentable) cited correctly — applies feedback_typed_state_carriers_arent_metadata_markers discipline
  • Live diagnostics.dag substrate cited at §4.2 — not "future T-Ground-Diagnostic NOT-STARTED" framing (the substrate IS live at src/v3/std/diagnostics.dag:150)
  • 2-input signature consistent across §2 / §3 / §9 — fn lower(surface: SurfaceModule, elaboration: ElaborationSpec) -> LowerResult
  • §6 PR-number disclaimer — lane-anchor primary; PR numbers freeze a snapshot

Sections

  1. Purpose + scope
  2. What lower IS structurally — 2-pass structural elaboration; NOT a decision engine
  3. Input types — SurfaceModule + ElaborationSpec (NEW carrier per Decision 3.C)
  4. Output types — PreInferDag (Decision 3.A typed-state) + LowerDiagnostic (Decision 2.B discriminated-union); LowerResult sum
  5. Structural elaboration — Pass 1 declarations+symtable / Pass 2 connectives+bodies
  6. Substrate prereqs — Gap-tier-anchored (lighter than PB-6's; mostly Decision 3.A dependent)
  7. Cross-stage coordination
  8. N/A — Shape A/B is emit's concern
  9. SELF_HOSTING.md §2.2 4-step applied to PB-4 (phased Step 4 per §12 Q5 — lower.rs is 11895 lines)
  10. Determinism preservation discipline
  11. Construction-time invariants (PreInferDag constructor enforces)
  12. Q1-Q6 open design questions for operator/PM ratification
  13. Non-goals
  14. Acceptance criteria
  15. Authoring sequence post-ratification
  16. Cross-references

§12 Q1-Q6 open questions

  • Q1 ElaborationSpec rule shape — closed-axis sum vs pattern-table-indexed
  • Q2 Symbol-table substrate carrier — NEW src/v3/std/symbol_table.dag shape
  • Q3 2-pass split — keep (recommended; decidability) or single-pass
  • Q4 PreInferDag construction-time invariants — constructor-only (recommended) vs builder+verify
  • Q5 Migration scope — full single-PR vs phased (recommended for 11895-line scope)
  • Q6 PB-3 parse dependency — independent (recommended; SurfaceModule carrier is stable)

Test plan

  • Operator/PM ratifies §12 Q1-Q6 per operator 2026-05-14 directive
  • Once §12 ratified, expanded-scope orientation brief for warm-wolf-698 cites this L2.5 as PB-4 design authority
  • PB-Substrate Decision 3.A landing first (cross-stage Dag = PreInferDag | InferredDag carrier extension)
  • Subsequent PB-4 worker brief authoring (by Director) cites named §-anchors in this doc

🤖 Generated with Claude Code

…ification

Director-tier L2.5 model for PB-4 lower per operator 2026-05-14
ratification:
- Decision 1.A scoping = Option A (pipeline-stage L2.5s = Director scope)
- "have pm sign off on everything" delegation for remaining decisions

Authors PB-4 lower-stage migration model:
- §3 input types: SurfaceModule (live at parse_surface.dag) +
  ElaborationSpec (NEW substrate per Decision 3.C .dag rules)
- §4 output types: PreInferDag (typed-state per Decision 3.A
  sum-variant) + LowerDiagnostic (per Decision 2.B
  discriminated-union); LowerResult = Either<PreInferDag,
  List<LowerDiagnostic>>
- §5 structural elaboration: 2-pass (Pass 1 = declarations +
  symbol table; Pass 2 = connectives + body lowering per
  ElaborationSpec rules)
- §6 prereqs: PB-Substrate Decision 3.A landing (sum-variant
  Dag extension); LowerDiagnostic variants extend live
  diagnostics.dag; ElaborationSpec NEW carrier
- §9 4-step: Step 1 = this doc; Step 2 = pipeline slot in
  compiler.dag; Step 3 = lower.dag + elaboration_spec.dag;
  Step 4 = parity vs lower.rs OUTPUT + simultaneous deletion
  (phased per §12 Q5 — lower.rs is 11895 lines)
- §12 Q1-Q6 open questions for operator/PM ratification

Authoring applied learnings from PR #3066 PB-6 emit L2.5 cycle:
- Grep-verified ALL substrate citations BEFORE authoring
- Typed-state carrier from start (PreInferDag per Decision 3.A)
- Practice 4 (Coproduct dissolution) + Practice 2 (illegal
  states unrepresentable) cited correctly
- Live diagnostics.dag substrate cited (not "future T-Ground")
- 2-input signature consistent across §2/§3/§9
- §6 PR-number disclaimer (lane-anchor primary)

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: 27ab0f6f · Trigger: schedule
  • Thinking: 200s wall

BLOCKING (2)

Root Cause

  • docs/design-lower-stage-l25-model.md diagnostic carrier shape was asserted from the ratification thread rather than verified against the live substrate → either add a PB-Substrate prereq that introduces the stage-tagged carrier first, or rewrite LowerDiagnostic against the current AnyDiagnosticKind/sibling-carrier model.
  • docs/design-lower-stage-l25-model.md lower failure semantics are split between graph-attached diagnostics and result-level diagnostics → define one structural output contract, either error-only with no returned unresolved PreInferDag or a result/product variant that carries the dag and diagnostics together.

⚠️ The model is close, but the lower diagnostic/output boundary needs to be reconciled before this becomes the Step 2 authority.


**Substrate authority**: `src/v3/std/elaboration_spec.dag` is a NEW substrate file PB-4 must author. Verified at this doc's HEAD via `grep -rn "type ElaborationSpec" src/v3/std/ dsl/std/` (no existing declaration). Per Decision 3.C operator-ratified shape, `ElaborationSpec` carries the rules as declared substrate, not as Rust closures.

**Lane dependency**: PB-Substrate (generates parse_surface.dag mirror + behavior carriers from substrate.dag); Director-tier substrate-fact-introduction for `ElaborationSpec` carrier itself.

This comment was marked as resolved.


### §3.3 Target identity NOT an input to lower

Lower is target-agnostic. Per `feedback_target_agnostic_ir`, the output `PreInferDag` carries no target-specific facts; target selection happens at emit time via LanguageSpec choice. Lower's job is the structural mapping; emit's job is the per-target inhabitance lookup.

This comment was marked as resolved.

@briansrls

Copy link
Copy Markdown
Contributor Author

Review metadata

  • Provider / model: openai-pro / gpt-5-5-pro
  • Commit: 27ab0f6f · Trigger: manual
  • Comparison: main @ 49631883 ... docs/director-pb4-lower-l25-model @ 27ab0f6f
  • Conversation: View conversation

1. Story of the diff

This PR adds a ratification draft for PB-4’s lower-stage model in docs/design-lower-stage-l25-model.md. The document’s core move is to stop treating lower as an opaque Rust pass and define it as a two-pass structural elaboration from (SurfaceModule, ElaborationSpec) into a pre-inference DAG: pass 1 allocates declarations/placeholders/symbols, and pass 2 turns each surface variant into L1 behavior through data-authored elaboration rules (docs/design-lower-stage-l25-model.md:31, docs/design-lower-stage-l25-model.md:57, docs/design-lower-stage-l25-model.md:147). It then lays out the substrate prerequisites (PreInferDag, LowerDiagnostic, symbol-table substrate, ElaborationSpec), the handoff contract to infer/emit, and the migration sequence from a temporary ExternalRealization over today’s lower.rs to .dag parity tests and deletion of lower.rs (docs/design-lower-stage-l25-model.md:167, docs/design-lower-stage-l25-model.md:187, docs/design-lower-stage-l25-model.md:212, docs/design-lower-stage-l25-model.md:214). That overall direction matches PB-to-zero: model the pass as data, use .dag TestClaim parity only as a bridge, then shrink the SG-0 hand-Rust census.

2. Invariant categories

1. LAYER MODEL — substrate vs implementation

Finding — BLOCKING, substrate output carrier / illegal states. The diff is not implementation-only; it proposes substrate-level carriers and later says the document becomes the authority for Step 2 and the §1.8 close criterion (docs/design-lower-stage-l25-model.md:332). The core result shape is internally inconsistent:

docs/design-lower-stage-l25-model.md:88: PreInferDag carries declarations + L1 behaviors + ports whose state is either Uninferred or Unresolved.

docs/design-lower-stage-l25-model.md:122: type LowerResult = Either<PreInferDag, List<LowerDiagnostic>>

docs/design-lower-stage-l25-model.md:155: The unresolved state propagates structurally; downstream infer/emit handle unresolved port fail-closed.

If unresolved identifiers are meant to produce both a PreInferDag with PortState::Unresolved and a diagnostic stream, Either<PreInferDag, List<LowerDiagnostic>> cannot represent the intended state. A faithful worker would have to choose between dropping the DAG on any diagnostic or dropping diagnostics to pass the DAG forward. That violates the doc’s own “facts flow forward” boundary contract. Either model unresolved lower output as a typed partial outcome carrying both DAG and diagnostics, or make lower diagnostics fatal and remove unresolved-state propagation from PreInferDag.

2. INVARIANTS.md + modeling-discipline.md

Finding — BLOCKING, P2 Boundary Discipline / P3 typed diagnostic carriers. The proposed diagnostic payload stringifies a closed structural fact:

docs/design-lower-stage-l25-model.md:51: Live type surface: SurfaceModule, SurfaceExpr, SurfacePattern, SurfaceItem are already closed-axis sums in parse_surface.dag.

docs/design-lower-stage-l25-model.md:57: ElaborationSpec is a declared authority that maps surface variants to Behavior construction recipes.

docs/design-lower-stage-l25-model.md:109: | UnsupportedSurfaceForm { form: String, reason: String }

docs/design-lower-stage-l25-model.md:147: Each SurfaceExpr / SurfacePattern variant has exactly one Behavior mapping.

form: String turns a closed-axis surface variant into string authority at the diagnostic boundary. The diagnostic should carry a typed surface-form tag/reference or a closed variant carrier, with optional human text as display detail. This is especially important because this doc is setting the substrate model, not just describing an implementation detail. The reference discipline requires typed failures and facts flowing forward rather than string/sentinel authority. chatgpt-review-5565acd2-3674-46…

chatgpt-review-e90ed09d-405f-43…

3. CODING.md

Compliant, with the result-shape defect counted above. The intended stage signature is explicit and data-shaped — fn lower(surface: SurfaceModule, elaboration: ElaborationSpec) -> LowerResult at docs/design-lower-stage-l25-model.md:212 — and Q4 rejects a mutable builder in favor of constructor-level enforcement at docs/design-lower-stage-l25-model.md:271–docs/design-lower-stage-l25-model.md:279. That matches the project’s data + functions / explicit dependencies style; the remaining issue is the exact LowerResult carrier, not the coding shape.

4. TESTING.md

Compliant. The diff does not add executable code, so no direct test addition is required in this PR. The migration plan correctly makes parity a .dag TestClaim bridge and explicitly dissolves it when lower.rs is deleted in the same PR (docs/design-lower-stage-l25-model.md:214, docs/design-lower-stage-l25-model.md:216). That matches the 0-floor testing direction: .dag test declarations are the long-term surface, and Rust-side harnesses are transitional. chatgpt-review-d578fe91-bf76-43…

5. LOCKED DESIGN DECISIONS

Compliant. The diff preserves Pure Bootstrap to Zero rather than weakening it: Step 3 authors src/v3/std/lower.dag and src/v3/std/elaboration_spec.dag (docs/design-lower-stage-l25-model.md:213), Step 4 deletes lower.rs and shrinks EXPECTED_HAND_AUTHORED_NON_TEST (docs/design-lower-stage-l25-model.md:214), and the authoring sequence closes only when lower.rs is deleted (docs/design-lower-stage-l25-model.md:350). I do not see a locked-design divergence. The live PB-zero authority sets zero hand-authored v3 source as the goal and treats lower as one of the compiler internals to migrate from hand Rust to .dag authority. chatgpt-review-11fa64ad-35c1-40…

chatgpt-review-3b34df0d-a8d5-41…

6. TRACKED vs UNTRACKED DEBT

Compliant for the explicit bridge; findings above are model defects, not tracked debt. The temporary ExternalRealization bridge is bounded to Step 2 (docs/design-lower-stage-l25-model.md:212), the parity bridge has a deletion trigger in Step 4 (docs/design-lower-stage-l25-model.md:214), and phased semantic deletions require their own parity plus dissolution receipts (docs/design-lower-stage-l25-model.md:293). That satisfies tracked-bridge discipline. The LowerResult inconsistency and UnsupportedSurfaceForm.form: String are not presented as temporary scaffolds with dissolution triggers, so they should be corrected before ratification rather than accepted as debt.

2.5. Top-down PM intent review

Finding — BLOCKING. At the PM level, the PR mostly preserves the PB-4 intent: it routes lower toward a .dag authority, not permanent Rust, and makes deletion of lower.rs part of the closure condition (docs/design-lower-stage-l25-model.md:213–docs/design-lower-stage-l25-model.md:214). The problem is that the document is also intended to become the authority for downstream worker briefs (docs/design-lower-stage-l25-model.md:332), and its result model would cause a worker who follows it faithfully to implement the wrong pipeline boundary: LowerResult = Either<PreInferDag, List<LowerDiagnostic>> at docs/design-lower-stage-l25-model.md:122 cannot express the same document’s unresolved-port-plus-diagnostic propagation contract at docs/design-lower-stage-l25-model.md:88 and docs/design-lower-stage-l25-model.md:155. That dilutes the top-level “facts are structural and flow forward” intent before the work is dispatched.

A second PM-level concern is the raw form: String diagnostic at docs/design-lower-stage-l25-model.md:109; because the same doc names closed surface sums and one-rule-per-variant elaboration (docs/design-lower-stage-l25-model.md:51, docs/design-lower-stage-l25-model.md:147), ratifying that string shape would steer workers toward a string-keyed diagnostic boundary where the project expects typed carriers.

3. Verdict

REQUEST_CHANGES. The overall PB-4 story is sound and the migration/debt plan is well tracked, but this document is a substrate authority draft. Before ratification, the lower result carrier needs to represent the intended DAG-plus-diagnostics state without ambiguity, and the unsupported-form diagnostic should carry a typed surface-form fact rather than stringifying a closed variant.

briansrls and others added 2 commits May 14, 2026 12:51
…ING #3077

Codex INLINE BLOCKING (line:74) correctly flagged that the prior
§4.2 + §6 framing misrepresented the live diagnostics substrate:

Verified facts (grep + Read):
- Line 150: `type Diagnostic { kind: AnyDiagnosticKind, span,
  message, correction }` — runtime carrier
- Line 139: `AnyDiagnosticKind = CompilerKind | LensInstanceKind`
  — discriminates by KIND-LAYER per Q6.5 anti-bridge, NOT by stage
  source
- Line 201: `EmissionDiagnostic` — SEPARATE carrier for emission
  fold failures (per PR #3066 §4.2; Q6.5 anti-bridge preserved)

Decision 2.B per-stage `source` axis is a SUBSTRATE EXTENSION
(NOT currently live). Prior framing as "live cross-stage carrier"
was wrong.

Fixed:

1. §4.2 reframed: live substrate state explicit + Decision 2.B
   substrate-extension framing + two extension paths surfaced
   (carrier-field vs lane-local-sum-mapping)

2. §6 prereq table T-LowerDiagnostic row updated: live state
   + extension path + Q6.5 anti-bridge preservation

3. Added §12 Q7 (NEW per codex BLOCKING): Decision 2.B
   DiagnosticSource substrate-extension path —
   (a) carrier field vs (b) lane-local sum + mapping. Director-
   recommend: (b) per Q6.5 anti-bridge + minimizing
   construction-site refactor.

4. §14 + §15 + §16 Q-list refs updated: Q1-Q7 (added Q7).

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

Copy link
Copy Markdown
Contributor Author

Codex INLINE BLOCKING (line:74, "live carrier is Diagnostic { kind: AnyDiagnosticKind, ... }; line 150 is EmissionDiagnostic; would extend wrong substrate authority") — substantively correct catch; fixed in commit 2bd0be8.

Verification (grep + Read src/v3/std/diagnostics.dag):

  • Line 150: type Diagnostic { kind: AnyDiagnosticKind, span: SourceSpan, message: String, correction: Correction } — runtime carrier (codex's "fixes" was the wrong field name; actual is "correction" — minor)
  • Line 139: type AnyDiagnosticKind = CompilerKind(CompilerDiagnosticKind) | LensInstanceKind(LensInstanceKindWitness) — discriminates by KIND-LAYER per Q6.5 anti-bridge (NOT by stage source)
  • Line 201: type EmissionDiagnostic = | UnderRefined | NoInhabitant | ... — SEPARATE carrier per Q6.5 anti-bridge (cited by PR docs(r3): PB-6 emit pipeline-stage L2.5 domain model — DRAFT for ratification #3066 §4.2 correctly)

The substantive issue: my §4.2 framing claimed Decision 2.B per-stage DiagnosticSource axis was live; it's actually a SUBSTRATE EXTENSION. The existing AnyDiagnosticKind discriminates orthogonally (kind-layer, not stage). Extending into the existing kind-axis would violate the Q6.5 anti-bridge invariant explicitly documented at line 135-141 (compiler-primitive vs lens-instance separation).

Fixes in commit 2bd0be8:

  1. §4.2 reframed: live substrate state explicit (Diagnostic carrier + AnyDiagnosticKind + EmissionDiagnostic structure); Decision 2.B per-stage source axis = SUBSTRATE EXTENSION (NEW); two extension paths surfaced: (a) carrier-field-extension source: DiagnosticSource on Diagnostic, (b) lane-local LowerDiagnostic sum mapping into CompilerKind per the line 163-168 anti-bridge pattern.

  2. §6 prereq table row updated: live state honest; extension path framed; operator/PM ratification needed.

  3. Added §12 Q7 NEW: Decision 2.B DiagnosticSource substrate-extension path — (a) carrier-field vs (b) lane-local-sum-mapping. Director-recommend: (b) per Q6.5 anti-bridge preservation + minimizing construction-site refactor cost.

  4. §14 + §15 + §16 Q-list refs updated: Q1-Q7 (added Q7).

PR #3085 (PB-5 infer L2.5) has the same erroneous citation; will fix in parallel.

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

briansrls added a commit that referenced this pull request May 14, 2026
…OCKING

Same fix as PR #3077 commit 2bd0be8 applied to PB-5 infer L2.5.

Codex INLINE BLOCKING #3077 line:74 identified that the live
diagnostics substrate at src/v3/std/diagnostics.dag has:
- Line 150: Diagnostic { kind: AnyDiagnosticKind, ... }
- Line 139: AnyDiagnosticKind = CompilerKind | LensInstanceKind
  (kind-layer discrimination per Q6.5 anti-bridge)
- Line 201: EmissionDiagnostic (separate per Q6.5)

Decision 2.B per-stage source axis is SUBSTRATE EXTENSION (not
live). PB-5 infer L2.5 had the same erroneous "live cross-stage
carrier" framing as PB-4 lower; both fixed.

Fixes:
1. §4.2 reframed: live state explicit + extension paths +
   reference to PR #3077 §12 Q7 for cross-stage ratification
2. §6 prereq table row updated with extension path framing
3. §16 cross-references updated with correct carrier citations

Per-stage diagnostic extension is now a CROSS-STAGE decision
(PR #3077 Q7) that applies uniformly to PB-2/3/4/5/6 — operator
ratification of Q7 disposition cascades across all pipeline-stage
L2.5 docs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codex INLINE BLOCKING line:78 correctly flagged that the
proposed `LowerResult = Either<PreInferDag, List<LowerDiagnostic>>`
contradicts §4.1 + §5.3 where PreInferDag itself carries
partial-failure (Unresolved ports with diagnostics in the
diagnostic table; Unresolved state propagates structurally).

The Either framing would make the Unresolved+ResolveError graph
either unreturnable (if Left was forced fully-Resolved) or
untyped at the infer boundary — violating
feedback_fail_closed_discipline + facts-flow-forward.

Fix:
1. §4.3 reframed: NO separate LowerResult sum-variant.
   PreInferDag itself IS the typed-state carrier with
   diagnostics coupled INTO it via biconditional `state ==
   Unresolved iff diagnostics.contains(port_id)`. Same pattern
   as PB-5 infer's InferredDag per PR #3085 §4.3.
2. §9 Step 2 row signature corrected:
   `fn lower(surface, elaboration) -> PreInferDag` (NOT
   LowerResult).
3. §16 memory-disciplines updated: feedback_fail_closed_discipline
   now framed as "diagnostics coupled INTO PreInferDag via
   biconditional" not "LowerResult sum-variant".

Cross-stage consistency: PB-4 lower + PB-5 infer both use
typed-state carrier with biconditional-coupled diagnostics.
PB-6 emit uses EmissionResult sum because emit produces
target-language source bytes (different output domain where
partial-source-with-error isn't a valid intermediate).

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

Copy link
Copy Markdown
Contributor Author

Codex INLINE BLOCKING (line:78, "Either<PreInferDag, List> contradicts the promised PreInferDag plus diagnostic stream, makes Unresolved+ResolveError graph either unreturnable or untyped at infer boundary") — substantively correct; fixed in commit 7b58fcc.

The earlier draft had an internal contradiction: §4.1 + §5.3 declared PreInferDag itself carries Unresolved ports + ResolveError diagnostics (partial-failure structural), but §4.3 wrapped it as Either<PreInferDag, List<LowerDiagnostic>> which forced an XOR with the partial-failure shape. Either Left was always fully-Resolved (contradicting §4.1) or Unresolved-ports leak through both Either arms (untyped at infer boundary).

Fix in commit 7b58fcc:

  1. §4.3 reframed: NO separate LowerResult sum-variant. PreInferDag itself IS the typed-state carrier; diagnostics couple INTO it via biconditional state == Unresolved iff diagnostics.contains(port_id) — same pattern as PB-5 infer's InferredDag per PR docs(r3): PB-5 infer pipeline-stage L2.5 domain model — DRAFT for ratification #3085 §4.3.

  2. §9 Step 2 signature corrected: fn lower(surface, elaboration) -> PreInferDag (NOT LowerResult).

  3. §16 memory-disciplines updated to reflect structural-coupling rather than sum-variant.

Cross-stage consistency:

The discriminator: when the output is a STRUCTURAL value (Dag-shape), partial-failure couples structurally. When the output is a FINAL ARTIFACT (target source bytes), partial-failure couples via Result sum.

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

@briansrls

Copy link
Copy Markdown
Contributor Author

High-level BLOCKING summary corresponding to 2 inline findings already addressed:

Finding 1 (diagnostic carrier shape verified against live substrate) — fixed in commit 2bd0be8:

  • Live Diagnostic { kind: AnyDiagnosticKind, ... } at line 150 (kind-layer discrimination per Q6.5 anti-bridge)
  • AnyDiagnosticKind = CompilerKind | LensInstanceKind at line 139
  • EmissionDiagnostic at line 201 (SEPARATE carrier per Q6.5)
  • Decision 2.B per-stage source axis is SUBSTRATE EXTENSION (NOT live)
  • §4.2 reframed + §12 Q7 (NEW) for cross-stage Decision 2.B extension path; Director-recommend (b) lane-local sum + mapping into CompilerKind

Finding 2 (output contract split between graph-attached and result-level) — fixed in commit 7b58fcc:

  • Dropped LowerResult = Either<PreInferDag, List<LowerDiagnostic>> (was internal contradiction with §4.1/§5.3)
  • §4.3 reframed: PreInferDag IS the typed-state carrier; diagnostics coupled INTO it via biconditional state == Unresolved iff diagnostics.contains(port_id)
  • Same pattern as PB-5 infer's InferredDag per PR docs(r3): PB-5 infer pipeline-stage L2.5 domain model — DRAFT for ratification #3085 §4.3
  • §9 Step 2 signature corrected: fn lower(surface, elaboration) -> PreInferDag

Cross-stage discipline: lower (this) + infer (PR #3085) use typed-state-with-coupled-diagnostics pattern (structural output domain); emit (PR #3066) uses Result sum (final-artifact output domain). Discriminator named in §4.3 prose.

Both findings replied at:

  • /issuecomment-4452767294 (diagnostic carrier)
  • /issuecomment-4452784466 (output contract)

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

OpenAI-pro REQUEST_CHANGES (sha 27ab0f6) BLOCKING finding 2:
`UnsupportedSurfaceForm { form: String, reason: String }`
stringifies a closed-axis surface variant. Per INVARIANTS P2
(Boundary Discipline) + P3 (typed diagnostic carriers) + the
project's typed-carrier discipline, diagnostic boundaries must
carry typed facts, not String.

The live substrate at src/v3/std/parse_surface.dag has closed-
axis sums: SurfaceExpr (line 149) / SurfaceItem (line 257) /
SurfacePattern (line 123) / SurfaceType (line 67) / SurfaceLiteral
(line 143). Diagnostic must reference these typed carriers.

Fix:

1. Added SurfaceFormRef typed reference sum:
   = ExprForm(SurfaceExpr)
   | ItemForm(SurfaceItem)
   | PatternForm(SurfacePattern)
   | TypeForm(SurfaceType)
   | LiteralForm(SurfaceLiteral)

2. Added IdentifierRef typed reference for resolve errors.

3. Updated LowerDiagnostic variant fields:
   - ResolveError.identifier: String → IdentifierRef
   - UnsupportedSurfaceForm.form: String → SurfaceFormRef
   - DuplicateDeclaration.name: String → NonEmptyStr
   - DuplicateRecordFieldLabel.label: String → NonEmptyStr

   reason: String preserved as human display detail per openai-pro's
   explicit allowance.

4. Discipline comment added: ALL variants carry typed closed-axis
   facts at boundaries, not String.

Cross-stage applicability: this same typed-carrier discipline applies
to PB-5 infer's InferDiagnostic; will propagate fix to PR #3085.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request May 14, 2026
Same typed-carrier discipline as PR #3077 commit 9feecac
applied to PB-5 infer InferDiagnostic per openai-pro's
INVARIANTS P2/P3 framing.

Fix:
- Added IdentifierRef typed reference (same as PB-4 lower)
- Added AlgebraAxisRef typed reference for AlgebraInhabitanceFail
- Updated InferDiagnostic.UnresolvedIdentifier.identifier: String → IdentifierRef
- Updated InferDiagnostic.AlgebraInhabitanceFail.axis: String → AlgebraAxisRef
- PostSweepUninferred.fallback_reason: String preserved as human
  display detail per openai-pro's explicit allowance

Discipline comment added: ALL classification fields are typed
closed-axis carriers, not String.

Cross-stage consistency: PB-4 lower (PR #3077) + PB-5 infer
(this) both use typed-carrier discipline at diagnostic
boundaries.

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

Copy link
Copy Markdown
Contributor Author

OpenAI-pro REQUEST_CHANGES (gpt-5-5-pro, sha 27ab0f6) — both BLOCKING findings now addressed:

Finding 1 (LowerResult inconsistency) — already fixed in commit 7b58fcc BEFORE this review arrived. §4.3 reframed: PreInferDag IS the typed-state carrier; diagnostics coupled INTO it via biconditional state == Unresolved iff diagnostics.contains(port_id). NO Either<PreInferDag, List> wrapping. §9 Step 2 signature corrected to fn lower(surface, elaboration) -> PreInferDag. (Already replied at /issuecomment-4452784466.)

Finding 2 (UnsupportedSurfaceForm.form: String stringifies closed-axis variant) — substantively correct + just fixed in commit 9feecac. Per INVARIANTS P2/P3 + project typed-carrier discipline:

  • Added SurfaceFormRef typed reference sum: ExprForm(SurfaceExpr) | ItemForm(SurfaceItem) | PatternForm(SurfacePattern) | TypeForm(SurfaceType) | LiteralForm(SurfaceLiteral) — closed-axis carriers per live parse_surface.dag
  • Added IdentifierRef typed reference for resolve errors
  • Updated all LowerDiagnostic variants: String classification fields → typed closed-axis references:
    • ResolveError.identifier: String → IdentifierRef
    • UnsupportedSurfaceForm.form: String → SurfaceFormRef
    • DuplicateDeclaration.name: String → NonEmptyStr
    • DuplicateRecordFieldLabel.label: String → NonEmptyStr
  • reason: String preserved as human display detail per your explicit allowance ("optional human text as display detail")
  • Discipline comment added: ALL classification fields are typed closed-axis carriers, NOT String

Cross-stage propagation: same typed-carrier discipline propagated to PB-5 infer's InferDiagnostic at PR #3085 commit a63062b — UnresolvedIdentifier.identifier: String → IdentifierRef, AlgebraInhabitanceFail.axis: String → AlgebraAxisRef.

The doc now satisfies:

  • INVARIANTS P2 (Boundary Discipline) — closed-axis variants typed at diagnostic boundary
  • INVARIANTS P3 (typed diagnostic carriers) — no String-keyed authority
  • Internal consistency — PreInferDag is the typed-state carrier; diagnostics couple structurally (no Either-wrapping contradiction)

Thank you for the careful audit — both findings caught real substrate-modeling errors that would have steered Step 2 workers toward String-keyed boundaries.

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

@briansrls

Copy link
Copy Markdown
Contributor Author

This is the openai-pro reviewer's operational log re-relayed (uploads, prompts, model-selector debug); the actual substantive review findings were already addressed in /issuecomment-4452802975 across commits 7b58fcc (LowerResult drop) + 9feecac (typed surface-form refs) + cross-stage propagation to PR #3085 at a63062b.

No new finding in this relay. Both openai-pro REQUEST_CHANGES findings stand resolved on current HEAD 9feecac; dashboard tally already shows rc=0 (REQUEST_CHANGES retired).

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

briansrls and others added 4 commits May 14, 2026 16:59
…boundary

Claude APPROVE exploratory obs2 (non-blocking):
"Q5 phase decomposition crosses pass boundaries — Pass-1
placeholder allocation can't be parity-tested in isolation."

Added per-phase parity witness shape clarification under
§12 Q5:

(b.i) Per-pass parity via typed intermediate-state carrier
(Pass1Output { declarations, symbol_table }) — parity asserts
pass1_via_rust == pass1_via_dag.

(b.ii) End-to-end per-phase with partial lower.rs deletion +
delegation — risks paper-shrink-relocation class.

Director-recommend (b.i) per Modeling Practice 2; Step 2
brief locks per-phase parity-witness carrier shape.

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

Codex REQUEST_CHANGES (/api/reviews/11913) correctly flagged:
§7.2 line 227 treated DiagnosticSource tagging as settled
("each stage emits diagnostics tagged with its DiagnosticSource")
while §4.2/§12 Q7 left the substrate-extension path unresolved
between (a) carrier-field vs (b) lane-local sum. That's two
incompatible authorities — P2 single-authority violation +
Practice 5 (single-authority metadata).

Fix: §7.2 rewritten to honestly defer to §12 Q7 ratification:
- "discriminable by source via whichever substrate-extension
  path §12 Q7 ratifies — (a) carrier-field OR (b) lane-local
  sum"
- "Whichever path lands, downstream stages can discriminate"
- "§12 Q7 must ratify before Step 2 worker brief authoring"

The discrimination axis is preserved (Parse/Lower/Infer/Emit
sources are still meaningful) but the substrate-extension path
is honestly marked as unresolved until §12 Q7 ratifies.

P2 single-authority restored: §12 Q7 is the SINGLE authority
on which extension path; §7.2 + §4.2 + §6 all defer to it.

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

Same P2 single-authority fix as PR #3077 commit d20e9fa
applied to PB-5 infer L2.5 §7.3. PR #3077 §12 Q7 is the
cross-stage authority for Decision 2.B extension path.

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

Copy link
Copy Markdown
Contributor Author

Codex REQUEST_CHANGES (/api/reviews/11913) — substantively correct catch + fixed in commit d20e9fa.

The contradiction was real: §7.2 line 227 treated DiagnosticSource tagging as settled cross-stage behavior ("each stage emits diagnostics tagged with its DiagnosticSource") while §4.2 + §12 Q7 left two unresolved extension paths (carrier-field vs lane-local sum). P2 single-authority violation + Practice 5 (single-authority metadata).

Fix in commit d20e9fa:

§7.2 rewritten to defer honestly to §12 Q7 ratification:

"each stage's diagnostics are discriminable by source (Parse / Lower / Infer / Emit) via whichever substrate-extension path §12 Q7 ratifies — (a) carrier-field source: DiagnosticSource on Diagnostic OR (b) lane-local sum mapping into AnyDiagnosticKind::CompilerKind. Whichever path lands, downstream stages can discriminate by stage source for context but do not need to re-process prior-stage diagnostics. §12 Q7 must ratify before Step 2 worker brief authoring — the worker brief authors against a SINGLE authoritative discrimination shape, not both paths."

The discrimination axis (Parse/Lower/Infer/Emit sources are meaningful) is preserved; the substrate-extension PATH is honestly marked as unresolved until Q7 ratifies. §12 Q7 is now the SINGLE authority on which extension path; §4.2 + §6 + §7.2 all defer to it.

Cross-stage propagation: same fix applied to PR #3085 PB-5 infer L2.5 §7.3 at commit 20fd2c8 — PR #3077 §12 Q7 is named as the cross-stage authority; PB-5 cannot unilaterally pick (a) or (b).

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

briansrls and others added 2 commits May 14, 2026 18:30
…-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>
… P5 receipt discipline

Two substantive findings per codex /api/reviews/12015:

1. §12 Q2: proposed `src/v3/std/symbol_table.dag` substrate carrier
   for a pass-local lookup structure (implementation tier). Per
   LAYER MODEL discipline (INVARIANTS + modeling-discipline):
   "if a type crosses a stage boundary or is consumed by a lens,
   it goes in std/; if it's internal to one stage's walk, it's
   implementation." Symbol table is internal-to-lower; over-
   modeling as substrate.

   Fix: Q2 reframed as RESOLVED inline — symbol table stays in
   implementation tier of `lower.dag` Step 3 work; no separate
   substrate carrier needed. Removed from §12 open-ratification
   list.

2. §12 Q5: phasing said "each phase = own parity test + dissolution
   receipt" but for refactor-only phases (e.g., Pass1Output
   exposure) there's no valid P5 receipt under the strict reading.
   P5 requires exactly ONE checkable receipt:
   - deleted scaffold path (SG-0 census shrink)
   - explicit deferral naming concrete ROADMAP.md row

   Refactor-without-deletion phases violate P5 without explicit
   deferral row.

   Fix: Q5 reframed with per-phase P5 receipt discipline explicit.
   Two corrected options:
   - (b.i) Each phase IS a deletion phase (or names explicit
     ROADMAP deferral row)
   - (b.ii) Single-PR migration (one P5 receipt covering all)
   Director-recommend flipped to (b.ii) if reviewer bandwidth
   allows; phased ONLY if each phase has valid P5 receipt.

   Removed "Pass1Output exposure" sub-option which violated P5
   under strict reading.

Updated §14 + §15 + §16 Q-list refs: Q1, Q3, Q4, Q5, Q6, Q7
(Q2 RESOLVED).

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

Copy link
Copy Markdown
Contributor Author

Codex REQUEST_CHANGES (/api/reviews/12015) — both findings substantively correct; fixed in commit b08285d.

Finding 1 (Q2 symbol-table over-modeled as substrate):

Per LAYER MODEL discipline (INVARIANTS + docs/modeling-discipline.md): "if a type crosses a stage boundary or is consumed by a lens, it goes in std/; if it's internal to one stage's walk, it's implementation." Symbol table is built by Pass-1, consumed by Pass-2, discarded at lower return — it's IMPLEMENTATION tier, not substrate.

Fix: §12 Q2 reframed as RESOLVED inline. Symbol table stays in implementation tier of lower.dag Step 3 work (local List/Map structure inside the recursive walk); no separate src/v3/std/symbol_table.dag carrier. Removed from §12 open-ratification list (Q1/Q3/Q4/Q5/Q6/Q7 remain open).

Finding 2 (Q5 phasing violates P5 receipt discipline):

P5 requires exactly ONE checkable receipt per PR:

  • deleted scaffold path (SG-0 census shrink)
  • explicit deferral naming concrete ROADMAP.md row

Earlier draft "Phase 4a expose Pass1Output via lower.rs refactoring without deletion" would EXPAND or PROLONG hand-Rust without naming a valid receipt — violates P5 strictly.

Fix: §12 Q5 reframed with per-phase P5 receipt discipline explicit. Two corrected options:

  • (b.i) corrected: each phase IS a deletion phase (some lower.rs section deleted + corresponding .dag substrate landing), OR names explicit ROADMAP deferral row for refactor-only phases
  • (b.ii) Single-PR migration: one PR with full lower.dag + all lower.rs deleted atomically; single P5 receipt covering entire migration

Director-recommend flipped to (b.ii) single-PR if reviewer bandwidth allows; phased ONLY if each phase has valid P5 receipt per closed-set above. Removed the "Pass1Output exposure" sub-option which violated P5 under strict reading.

Substantive learning logged: my prior Q5 framing prioritized risk-management on diff-size axis over P5-receipt-discipline axis. Codex correctly surfaced that the latter is the load-bearing axis.

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

briansrls and others added 4 commits May 14, 2026 14:38
…radictions

Cursor APPROVE_WITH_COMMENTS (/api/reviews/12049) caught two
internal contradictions left after my Q2 + Q7 fixes:

1. §6 prereq table still listed "Symbol-table substrate" with
   "Director-tier substrate-fact-introduction" — contradicts
   §12 Q2 RESOLVED (implementation tier, no carrier).

2. §16 cross-references said diagnostics.dag "extends with
   LowerDiagnostic variants" — overspecifies extension path
   that §12 Q7 explicitly leaves to ratification.

Both remnants from before my Q2/Q7 fixes; per
feedback_discipline_change_audit_all_contract_mentions
discipline, audit ALL sections when flipping a section.

Fix:
1. §6 Symbol-table row marked DROPPED with reasoning citing
   §12 Q2 RESOLVED + LAYER MODEL discipline. §6 critical-
   observation updated: "PB-4 has 4 prereqs" (was 5) + symbol-
   table noted as implementation-tier.
2. §16 LowerDiagnostic reference reframed to honor §12 Q7
   open-path framing: cites live Diagnostic shape + Q7 path
   "Director-recommend (b) lane-local sum; Q7 explicitly
   leaves path to ratification".

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

Copy link
Copy Markdown
Contributor Author

Review metadata

  • Provider / model: openai-pro / gpt-5-5-pro
  • Commit: 53664653 · Trigger: manual
  • Comparison: main @ 055b1b60 ... docs/director-pb4-lower-l25-model @ 53664653
  • Conversation: View conversation

1. Story of the diff

This PR adds a new ratification draft, docs/design-lower-stage-l25-model.md, that defines PB-4 lower as a modeled pipeline-stage migration rather than an implementation rewrite. The doc frames lower as a two-pass structural elaboration from (SurfaceModule, ElaborationSpec) -> PreInferDag, where pass 1 allocates declaration placeholders and a local symbol table, and pass 2 fills connectives and lowers bodies into L1 behaviors (docs/design-lower-stage-l25-model.md:31). The load-bearing move is that previously implicit lowering decisions become declared ElaborationSpec substrate facts, while the symbol table is explicitly demoted back to implementation tier rather than a new exported substrate carrier (docs/design-lower-stage-l25-model.md:57, docs/design-lower-stage-l25-model.md:295-299). The doc also applies the self-hosting four-step migration shape: declare a compiler slot, author lower.dag plus elaboration_spec.dag, then prove parity against current lower.rs output and delete the hand-Rust implementation in the same migration path (docs/design-lower-stage-l25-model.md:248-252).

2. Invariant categories

1. LAYER MODEL — Finding (BLOCKING)

docs/design-lower-stage-l25-model.md:136-140 defines LowerDiagnostic variants for both port-resolution failures and non-port failures:

ResolveError, UnsupportedSurfaceForm, DuplicateDeclaration, DuplicateRecordFieldLabel

but docs/design-lower-stage-l25-model.md:155-156 then says:

Port.state == Unresolved iff diagnostics.contains(port_id)

LowerDiagnostic variants live in the PreInferDag's diagnostic table indexed by port_id

That over-constrains the diagnostic substrate to a port-indexed authority even though several declared lower diagnostics are not port facts. A duplicate declaration, duplicate record field, unsupported item, or unsupported pattern may not have a meaningful PortId; forcing it through a port-indexed table either fabricates a port anchor or makes those diagnostics unrepresentable. Because this is a substrate/output-carrier model for PB-4, it should be fixed before ratification: either narrow the biconditional/table to ResolveError-style port diagnostics only, or introduce a typed DiagnosticAnchor = Port(PortId) | Declaration(DeclarationId) | Field(...) | SurfaceForm(...) shape and state the port biconditional only for the Port anchor.

2. INVARIANTS.md + modeling-discipline.md — Finding (BLOCKING)

Same issue through the invariant lens: this violates P2 Boundary Discipline and P3 Fail-Closed. The diff correctly tries to make diagnostics typed (docs/design-lower-stage-l25-model.md:116-141), but then collapses all lower diagnostics into a port_id-keyed table (docs/design-lower-stage-l25-model.md:155-156). That means the typed failure carrier is not actually single-authority for non-port lower failures, and fail-closed handling of unsupported surface forms or duplicate declarations depends on an unrelated port anchor. The fix is to make the diagnostic anchor typed at the same level as the diagnostic variants, not to route every variant through Port.state.

3. CODING.md — N/A

N/A — the PR adds a design document only; it explicitly does not author the .dag implementation or pipeline-slot code in this change (docs/design-lower-stage-l25-model.md:17-20). The planned signature is still function-shaped rather than object-shaped (docs/design-lower-stage-l25-model.md:248), but there is no new Rust implementation to review against CODING.md.

4. TESTING.md — Compliant

Compliant — for a Step 1 design doc, the testing obligation is modeled rather than implemented here: Step 4 requires a .dag TestClaim parity check comparing lower_via_rust(surface) to lower_via_dag(surface, elaboration_spec), and it couples that receipt to simultaneous lower.rs deletion (docs/design-lower-stage-l25-model.md:250). The doc also guards against paper-shrink by requiring parity against current lower.rs output rather than against a template relocation (docs/design-lower-stage-l25-model.md:252).

5. LOCKED DESIGN DECISIONS — Compliant

Compliant — the diff preserves the Pure Bootstrap to Zero direction by routing PB-4 through .dag implementation plus Rust deletion, not by adding a permanent hand-authored lower path (docs/design-lower-stage-l25-model.md:7, docs/design-lower-stage-l25-model.md:248-250). It also keeps lower target-agnostic, leaving target identity to emit (docs/design-lower-stage-l25-model.md:76-78, docs/design-lower-stage-l25-model.md:233).

6. TRACKED vs UNTRACKED DEBT — Compliant

Compliant — the transitional ExternalRealization placeholder is bounded by the four-step migration path (docs/design-lower-stage-l25-model.md:248), and the parity scaffolding gets a named dissolution trigger: it dissolves with lower.rs deletion in the same PR (docs/design-lower-stage-l25-model.md:250). The phasing section also explicitly rejects refactor-only phases unless they carry a concrete ROADMAP deferral, and recommends deletion-bearing phases or one atomic migration (docs/design-lower-stage-l25-model.md:333-353).

2.5. Top-down PM intent review

Finding (BLOCKING). The high-level intent is preserved in most of the doc: PB-4 is steered toward .dag authority, typed stage boundaries, no permanent hand-Rust, and parity-backed deletion. The diagnostic anchoring bug, however, would cause a worker to execute the wrong substrate model even if they followed the document faithfully: the plan lists non-port diagnostics such as DuplicateDeclaration and DuplicateRecordFieldLabel (docs/design-lower-stage-l25-model.md:139-140) but then places all LowerDiagnostic variants in a port-indexed table with a port-state biconditional (docs/design-lower-stage-l25-model.md:155-156). That dilutes the PM-level fail-closed/single-authority intent from INVARIANTS.md:12-13, because non-port lower failures either become impossible to represent or require fabricated port authority.

3. Verdict

REQUEST_CHANGES. The document is otherwise coherent and substantially aligned with PB-4/Pure Bootstrap discipline, but the diagnostic carrier/table model is a blocking substrate issue. Fix the diagnostic anchoring before ratification so Step 2/3 workers do not build the wrong lower-stage output contract.

@briansrls

Copy link
Copy Markdown
Contributor Author

openai-pro reviewer operational log relayed; actual review verdict not yet posted in this artifact (still uploading context files + filling prompt at 19:13). Will address findings when the substantive verdict arrives.

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

Openai-pro REQUEST_CHANGES (/api/reviews/12103) correctly flagged
that §4.3 + §9 Step 2 over-constrained LowerDiagnostic to
port-keyed table while declared variants include non-port
diagnostics:
- DuplicateDeclaration (declaration-level)
- DuplicateRecordFieldLabel (field-level)
- UnsupportedSurfaceForm (surface-form-level)

Forcing these through port-indexed table either fabricates port
anchor or makes them unrepresentable. P2 single-authority + P3
fail-closed violations.

Fix: introduce typed `DiagnosticAnchor` closed-axis sum:
  type DiagnosticAnchor
    = PortAnchor { port_id: PortId }
    | DeclarationAnchor { declaration_id: DeclarationId }
    | RecordFieldAnchor { declaration_id: DeclarationId, field: NonEmptyStr }
    | SurfaceFormAnchor { form: SurfaceFormRef, span: SourceSpan }

PreInferDag's diagnostic table is anchored: each entry has
`{ anchor: DiagnosticAnchor, diagnostic: LowerDiagnostic }`.

The Port-state biconditional `Port.state == Unresolved iff
diagnostics.contains(anchor: PortAnchor)` applies ONLY to port-
anchored diagnostics, NOT to all variants.

Updates:
1. §4.3 reframed with typed DiagnosticAnchor + biconditional
   scoped to PortAnchor
2. §9 Step 2 row signature note updated to reference
   anchor-typed diagnostic table (NOT port-only biconditional)

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

Copy link
Copy Markdown
Contributor Author

Openai-pro REQUEST_CHANGES (/api/reviews/12103) — substantively correct catch; fixed in commit b812db9.

The biconditional Port.state == Unresolved iff diagnostics.contains(port_id) over-constrained LowerDiagnostic to port-keyed table while §4.2 declared variants include non-port-keyed diagnostics:

  • DuplicateDeclaration (declaration-level)
  • DuplicateRecordFieldLabel (field-level)
  • UnsupportedSurfaceForm (surface-form-level)

Forcing these through port-indexed table fabricates port anchors or makes them unrepresentable — P2 single-authority + P3 fail-closed violations.

Fix in commit b812db9: introduced typed DiagnosticAnchor closed-axis sum + scoped biconditional:

type DiagnosticAnchor
  = PortAnchor { port_id: PortId }
  | DeclarationAnchor { declaration_id: DeclarationId }
  | RecordFieldAnchor { declaration_id: DeclarationId, field: NonEmptyStr }
  | SurfaceFormAnchor { form: SurfaceFormRef, span: SourceSpan }

// PreInferDag diagnostic table is anchor-typed, not port-only
// Biconditional applies ONLY to PortAnchor:
//   Port.state == Unresolved iff diagnostics.contains(anchor: PortAnchor)
// Non-port-anchored diagnostics live in the table without port-state coupling

§9 Step 2 row signature note updated to reference anchor-typed table.

Sibling-doc audit:

The fix is isolated to PB-4 lower where multi-kind diagnostics (port + declaration + field + form) genuinely require typed anchors.

Substantive learning: when propagating "biconditional X iff Y" patterns across stages, verify the diagnostic kinds at each stage are uniformly anchored. Different stages have different anchor structures (parse = span-level / lower = multi-anchor / infer = port-only / emit = different output domain).

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

@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: d20e9fa8 · Trigger: schedule
  • Thinking: 278s wall

BLOCKING (3)

Root Cause

  • docs/design-lower-stage-l25-model.md Live diagnostic substrate was re-read only for the source-axis question → preserve the existing { kind, span, message, fixes: List<Correction> } shape everywhere and add only the ratified source/mapping axis.
  • docs/design-lower-stage-l25-model.md The design elevated the lower.rs top-comment seed without the full collect_symbols/lower_item distinction → model declaration-bearing SurfaceItem variants separately from Bind/module/import implementation facts.
  • docs/design-lower-stage-l25-model.md ElaborationSpec was framed from expression-to-behavior lowering rather than the full lower output algebra → widen it to cover declaration/connective/pattern-binding recipes or split explicit rule families.

⚠️ The prior output-boundary blockers are addressed, but the Step 2 authority would still mis-state live diagnostic facts and under-model lower's non-Behavior outputs.

- `Match` → `Branch` with N Paths per arm (existing handling per `lower.rs` body)
- `Block` → composed `Bind` chain via sequencing
- (additional rules per `lower.rs` — Step 2 brief authors against full rule set; this enumeration is the seed from the top-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.

BLOCKING: The proposed Diagnostic extension replaces the live fixes: List<Correction> carrier with singleton correction: Correction, silently dropping the existing DB-1 correction-list fact at the diagnostic boundary (INVARIANTS P2 facts-flow-forward).

| TypeForm(SurfaceType)
| LiteralForm(SurfaceLiteral)

// Typed identifier reference for resolve errors (identifier-as-typed-fact,

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: §5.1 says every SurfaceItem variant maps 1:1 to a Declaration placeholder, but live lower.rs explicitly skips Let/Module/Import in collect_symbols, so the model would add declarations for non-declaration surface facts (INVARIANTS P1/P2).


**Lower is a 2-pass structural elaboration from (SurfaceModule, ElaborationSpec) → PreInferDag — first pass allocates Declaration placeholders + builds symbol table; second pass fills connectives + lowers function/let bodies to L1 behaviors. NOT a type-checking stage (infer's responsibility) and NOT a decision engine.**

Per `feedback_lenses_not_passes`: lower is a structural mapping from surface forms to substrate behaviors, not a decision process. Anything lower has to "decide" is an ElaborationSpec rule that should be declared in `.dag`, not encoded in lowering logic.

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: ElaborationSpec is defined as mapping SurfaceItem and SurfacePattern variants to Behavior recipes, but lower also constructs Declarations, TypeConnectives, BranchPatterns, and bindings, leaving non-Behavior lowering decisions outside the declared authority (THESIS substrate ownership; INVARIANTS 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: b812db91 · Trigger: schedule
  • Thinking: 200s wall

BLOCKING (1)

Root Cause

  • docs/design-lower-stage-l25-model.md Diagnostic substrate shape was repaired around anchoring but not re-audited as new substrate type declarations → add per-type dissolution classifications before this doc becomes the Step 2 authority.

⚠️ The prior output-boundary fixes are partly landed, but the new diagnostic substrate sums still need coproduct-discipline receipts before ratification.

```
// Typed diagnostic anchor — closed-axis sum over anchor kinds:
type DiagnosticAnchor
= PortAnchor { port_id: PortId }

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 proposed substrate coproducts in §4.2/§4.3 introduce DiagnosticSource, SurfaceFormRef, LowerDiagnostic, and DiagnosticAnchor without 🟢/🟡/🔴 dissolution receipts, so Step 2 would author new substrate sums without Modeling Practice 4 classification.

@briansrls
briansrls merged commit 55a4c7c into main May 15, 2026
4 checks passed
briansrls added a commit that referenced this pull request May 15, 2026
…ification (#3085)

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

Director-tier L2.5 model for PB-5 infer per operator 2026-05-14
ratification (Decision 1.A scoping = Option A; "harder/more correct"
directive).

Authors PB-5 infer-stage migration model:
- §2 substrate-driven inference: dispatching on TypeConnective IS
  substrate-driven; no separate "InferenceSpec" carrier (cf. PB-4's
  ElaborationSpec) needed — the rule book IS the substrate
- §3 input: PreInferDag per Decision 3.A
- §4 output: InferredDag (typed-state enforcement per Decision 3.A
  sum-variant; constructor rejects Uninferred). NO separate InferResult
  sum-variant — diagnostics coupled INTO InferredDag via the
  state==Unresolved-iff-diagnostics biconditional
- §5 forward propagation via TypeConnective dispatch + post-sweep
  fail-closed + anonymous-instantiation Builder pattern
- §6 prereqs: PB-Substrate Decision 3.A landing + algebra inhabitance
  fold + PM-authored amendment PR per disposition β
- §9 4-step: Step 2 = fn infer(PreInferDag) -> InferredDag;
  Step 3 = infer.dag; Step 4 = phased deletion per §12 Q5
- §12 Q1-Q6 open questions (forward-only vs constraint-solving; Builder
  vs fixed-point; post-sweep diagnostic specificity; ordering;
  phasing; PB-4 dependency)

Applied PR #3066 + PR #3077 review-cycle learnings:
- Grep-verified ALL substrate citations BEFORE authoring
- Typed-state carrier from start
- Practice 4 (Coproduct dissolution) + Practice 2 (illegal states) cited correctly
- Live diagnostics.dag substrate
- 4-param compile-aware signature (infer is internal to compile chain)
- Section-anchor citations for stable cross-references

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

* docs(r3): fix PB-5 §4.2 diagnostic substrate citation per PR #3077 BLOCKING

Same fix as PR #3077 commit 2bd0be8 applied to PB-5 infer L2.5.

Codex INLINE BLOCKING #3077 line:74 identified that the live
diagnostics substrate at src/v3/std/diagnostics.dag has:
- Line 150: Diagnostic { kind: AnyDiagnosticKind, ... }
- Line 139: AnyDiagnosticKind = CompilerKind | LensInstanceKind
  (kind-layer discrimination per Q6.5 anti-bridge)
- Line 201: EmissionDiagnostic (separate per Q6.5)

Decision 2.B per-stage source axis is SUBSTRATE EXTENSION (not
live). PB-5 infer L2.5 had the same erroneous "live cross-stage
carrier" framing as PB-4 lower; both fixed.

Fixes:
1. §4.2 reframed: live state explicit + extension paths +
   reference to PR #3077 §12 Q7 for cross-stage ratification
2. §6 prereq table row updated with extension path framing
3. §16 cross-references updated with correct carrier citations

Per-stage diagnostic extension is now a CROSS-STAGE decision
(PR #3077 Q7) that applies uniformly to PB-2/3/4/5/6 — operator
ratification of Q7 disposition cascades across all pipeline-stage
L2.5 docs.

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

* docs(r3): typed reference carriers per PR #3077 openai-pro BLOCKING

Same typed-carrier discipline as PR #3077 commit 9feecac
applied to PB-5 infer InferDiagnostic per openai-pro's
INVARIANTS P2/P3 framing.

Fix:
- Added IdentifierRef typed reference (same as PB-4 lower)
- Added AlgebraAxisRef typed reference for AlgebraInhabitanceFail
- Updated InferDiagnostic.UnresolvedIdentifier.identifier: String → IdentifierRef
- Updated InferDiagnostic.AlgebraInhabitanceFail.axis: String → AlgebraAxisRef
- PostSweepUninferred.fallback_reason: String preserved as human
  display detail per openai-pro's explicit allowance

Discipline comment added: ALL classification fields are typed
closed-axis carriers, not String.

Cross-stage consistency: PB-4 lower (PR #3077) + PB-5 infer
(this) both use typed-carrier discipline at diagnostic
boundaries.

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

* docs(r3): cursor PR #3085 observations — infer.rs line count + Q2 builder note

Cursor APPROVE exploratory observations (non-blocking):

1. §12 Q5 line count: "~8000+ lines" → "7262 lines"
   (verified via wc -l at this doc's HEAD)

2. §12 Q2 Builder clarification: added CODING.md-fluent-builder
   note distinguishing the substrate-owned typed-state
   accumulator pattern (data + free functions per CODING.md)
   from Rust-side fluent BuilderPattern anti-discipline.
   "Builder" terminology is conceptual (accumulator), not the
   fluent-chain anti-pattern.

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

* docs(r3): fix §7.3 DiagnosticSource P2 contradiction (companion to PR #3077)

Same P2 single-authority fix as PR #3077 commit d20e9fa
applied to PB-5 infer L2.5 §7.3. PR #3077 §12 Q7 is the
cross-stage authority for Decision 2.B extension path.

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

* docs(r3): cursor PR #3085 factual fixes — line count drift + §12.6 citation

Two non-blocking factual findings per cursor /api/reviews/11985:

1. infer.rs line count "7262" wrong (drifted to 7283 via main
   merges). Replaced with "~7300" + drift acknowledgment ("verify
   at Step 2 brief time").

2. §12.6 citation: §12.6 tables only the 4 pipeline stages
   (emit→lower→infer→parse); tokenize is per PB-2 lane in
   design-pure-bootstrap-zero.md, NOT §12.6. Reframed citation.

Per INVARIANTS P1 — documentation must not overstate authority.

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)

Same fix as PR #3077 commit 6be8bd7 propagated to PB-5 infer.

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

* docs(r3): fix codex PR #3085 BLOCKING — AlgebraAxis closed-axis enum (NOT String wrapper)

Codex REQUEST_CHANGES (/api/reviews/12088) correctly flagged the
contradiction: I claimed typed-carrier discipline but defined
`type AlgebraAxisRef = AlgebraAxis(NonEmptyStr)` — a String
wrapper masquerading as typed. That violates INVARIANTS P2/P3 +
Practices 5/6 + creates a second authority on algebra identity.

Fix: replaced `AlgebraAxisRef = AlgebraAxis(NonEmptyStr)` with
proper closed-axis enum:

  type AlgebraAxis
    = Closure
    | Associativity
    | Commutativity
    | Identity
    | Inverse
    | Distributivity
    | OrderingTotality
    | OrderingTransitivity
    | OrderingAntisymmetry

Adjacent to verification.dag:146 `AlgebraicLawKind` which has
the 3-variant subset (Associativity / Commutativity / Identity)
already live; this is the broader algebra-inhabitance failure
enumeration. Step 2 brief enumerates full closed set against
infer.rs check sites.

Substantive learning: when introducing typed reference carriers
to satisfy typed-carrier discipline, the carrier ITSELF must be
typed — wrapping String in a single-variant sum still leaks
String authority through the boundary.

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
…ification (#3126)

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

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>

* 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): fix codex INLINE BLOCKING #3126 — live state honesty

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>

* 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>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request May 15, 2026
… 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>
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
…stic 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>
@briansrls

Copy link
Copy Markdown
Contributor Author

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

Cursor's claim: "live fixes: List<Correction> carrier... existing DB-1 correction-list fact"

Verified live state at HEAD (grep -n "correction\|fixes\|^type Correction" src/v3/std/diagnostics.dag):

  • Line 67: type Correction = LiveCorrection { witness: CorrectionWitness } | DeferredCorrection { reason, retirement_plan: RetirementPlan } — Correction is a SUM-VARIANT (2 arms), NOT a list
  • Line 154: correction: Correction in Diagnostic record — SINGULAR field, NOT fixes: List<Correction>
  • grep returns NO fixes: field declaration in diagnostics.dag

There is NO fixes: List<Correction> carrier in live state. The DB-1 "correction-list fact" cursor references doesn't exist as a list — DB-1's source-level live correction is the LiveCorrection { witness } ARM of the Correction sum-variant, and Diagnostic carries ONE Correction value.

My PR #3077 doc cite at line 71 (commit a9a6d68 + b812db9) matches live state exactly:

type Diagnostic { kind: AnyDiagnosticKind, span: SourceSpan, message: String, correction: Correction } — line 150-155

Same reviewer-stale-context issue as PR #3085 line:83 finding (replied at /issuecomment-4455974096). Reviewer-side appears to have ingested a snapshot where fixes: List<Correction> was a proposed-but-unmerged shape; live HEAD has the singular correction: Correction shape.

No fix-forward needed for this finding; doc citation is correct.

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

briansrls added a commit that referenced this pull request May 15, 2026
…on 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>
briansrls added a commit that referenced this pull request May 15, 2026
…adened

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>
@briansrls

Copy link
Copy Markdown
Contributor Author

Codex high-level BLOCKING (sha d20e9fa) — all 3 findings cluster with cursor inline relays earlier this batch + already addressed via PR #3138 or verified incorrect:

Finding 1 (preserve fixes: List<Correction> shape): re-verified — the ONLY fixes mention in src/v3/std/diagnostics.dag is at line 145 in a DOC-COMMENT ("the diagnostic carrier, including fixes"). The ACTUAL field is correction: Correction at line 154 (singular; references the Correction = LiveCorrection | DeferredCorrection sum-variant at line 67).

There's a legacy doc-comment terminology drift IN diagnostics.dag itself (comment says "fixes", code says "correction"). My doc cite (correction: Correction) faithfully matches the CODE field. Reviewer-side context appears to be sourcing the "fixes" terminology from the legacy doc-comment rather than the actual code field. Already replied at /issuecomment-4455987326.

Finding 2 (collect_symbols/lower_item distinction): addressed in PR #3138 commit 61e2b67. §5.1 reframed: DeclarationAllocating variants (Fn / FnExternalBody / Data / TypeAtom / TypeRecord) vs NonDeclarationAllocating variants (Let / Module / Import skip per live lower.rs:2956-2958). Per cursor INLINE BLOCKING line:130.

Finding 3 (ElaborationSpec scope widening): addressed in PR #3138 commit 2808456. §3.2 ElaborationSpec scope broadened to ALL 5 lowering-decision axes (Declarations / TypeConnectives / Behaviors / BranchPatterns / Bindings). Per cursor INLINE BLOCKING line:33.

All substantive findings addressed; finding 1 found incorrect after re-verification. PR #3138 covers fix-forward.

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

briansrls added a commit that referenced this pull request May 15, 2026
…ions 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>
briansrls added a commit that referenced this pull request May 15, 2026
… 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>
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
…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
Same edits as PR #3138 commit e9739ea's tokenize-doc portion ported to
this PR's branch.

Finding 2 — TokenizeDiagnostic coproduct receipt:
Added 🟡 SCAFFOLD classification + dissolution trigger (tokenize-stage only:
Step 2 enumerates against tokenize_generated.rs:96 Diagnostic::* sites) +
anti-bridge note per Q6.5.

Finding 3 — Q7 reconciliation:
§4.2 "Lane dependency", §15 step 3, and §14 "Surfaces awaiting" now all
annotate Q7 as DONE 2026-05-15T00:21:19Z (PR #3077 merge timestamp);
TokenizeDiagnostic per-stage variant authoring is the remaining lane work.

(Finding 1 — infer-doc cross-stage trigger leak — does not apply to this
branch; it lives on PR #3138's branch which carries the infer L2.5 doc.)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request May 15, 2026
…iting 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>
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
@briansrls
briansrls deleted the docs/director-pb4-lower-l25-model branch June 1, 2026 18:41
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