Skip to content

docs(r3): PB-6 emit pipeline-stage L2.5 domain model — DRAFT for ratification - #3066

Merged
briansrls merged 23 commits into
mainfrom
docs/director-pb6-emit-l25-model
May 14, 2026
Merged

briansrls merged 23 commits into
mainfrom
docs/director-pb6-emit-l25-model

Conversation

@briansrls

Copy link
Copy Markdown
Contributor

Summary

  • Director-tier L2.5 domain model for PB-6 emit pipeline stage per operator directive 2026-05-14 ("we should be on the hook for providing the actual briefs/designs up front").
  • 349 lines / 16 sections. DRAFT status awaiting operator ratification of §12 Q1-Q6 open design questions.
  • Unblocks PB-6 lane execution authority dispatch via R3 Substrate Mgr (warm-wolf-698) under operator-ratified expanded scope (8 PB-X sub-program absorption per 2026-05-13 α-ratification).

Context

Per SELF_HOSTING.md §2.2 gating rule 4: PB-6 emit-stage L3 .dag substrate work cannot start until this L2.5 is reviewed. Paper-shrink discovery 2026-05-13 (template-relocation + module-relocation variants observed across cycles 3-REDO/4/5/6 → PRs #3046/#3048/#3056/#3057/#3058 closed or reverted) surfaced that retirement cycles were running without L2.5 design authority. Operator directive: Director authors L2.5 designs UP FRONT before any lane execution dispatch.

Sections

  1. Purpose — why PB-6 emit needs an L2.5
  2. Structural framing — emit = projection, not decision engine (per feedback_lenses_not_passes)
  3. Input types — Dag, LanguageSpec, EmissionConfig
  4. Output types — TargetSource, EmissionDiagnostic sum-variant, EmissionResult
  5. Structural projection composed via fold
  6. Substrate prereqs — Gap-tier-anchored (5 of 7 route through Gap 13 R3 Grounding Mgr lane)
  7. Cross-stage coordination — pipeline-slot ExternalRealization boundary
  8. Two-Shape framing — Shape A (compiler targets) vs Shape B (user-space artifacts)
  9. SELF_HOSTING.md §2.2 4-step applied to PB-6
  10. D-1 determinism invariant
  11. Cost lens consistency
  12. Q1-Q6 open design questions for operator ratification
  13. Non-goals
  14. Acceptance criteria
  15. Authoring sequence
  16. Cross-references

§12 Q1-Q6 open questions (operator ratification needed)

The §12 questions surface the design decisions where I want explicit operator ratification before warm-wolf-698 dispatches PB-6 workers. Listed in §12 of the doc.

What this PR is NOT

  • Not a PB-6 implementation PR. This is the L2.5 design document only.
  • Not test-deletion framework. That's a separate Director-authoring track for the testgen-subsumption + T-α/T-β/T-γ/T-δ classification.
  • Not the other 7 PB-X lane L2.5s (PB-3 parse, PB-4 lower, PB-5 infer, PB-Substrate, PB-Bootstrap-Process, PB-Runtime, PB-Lib+PB-Build) — pending operator scoping decision on Option A (Director pipeline-stage + Mgr substrate/runtime) vs Option B (Director all 9).

Test plan

  • Operator reviews §12 Q1-Q6 and ratifies / requests revisions
  • Once §12 ratified, expanded-scope orientation brief for warm-wolf-698 cites this L2.5 as PB-6 design authority
  • Subsequent PB-6 worker brief authoring (by warm-wolf-698) cites named §-anchors in this doc

🤖 Generated with Claude Code

briansrls and others added 2 commits May 14, 2026 05:50
…fication

Director-tier L2.5 model authoring per operator directive 2026-05-14
("we should be on the hook for providing the actual briefs/designs up front").

Surfaces emit-stage migration model for PB-6 lane execution authority
dispatch via R3 Substrate Mgr (warm-wolf-698) under operator-ratified
expanded scope (8 PB-X sub-program absorption).

DRAFT status — awaits operator ratification of §12 Q1-Q6 open design
questions before warm-wolf-698 dispatches PB-6 emit-stage workers.

Per SELF_HOSTING.md §2.2 gating rule 4: PB-6 emit-stage L3 .dag substrate
work cannot start until this L2.5 is reviewed.

Pairs with: paper-shrink discovery 2026-05-13 → cycles 4/5/6 reverted
(PR #3059) + cycle 3 REDO closed (PR #3056) + Director-authored L2.5
designs UP FRONT framework.

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

1. THESIS.md §1505 cite is broken (anchor does not exist; Shape A/B
   framing lives in docs/thesis/what-else-falls-out.md §"Two shapes of
   omni-emission" + normal THESIS.md headings). Replaced all 3 cites
   (§3.2, §8, §16) with the correct anchor.

2. PortState description was wrong. Actual variants per infer.rs:
   - Resolved(TypeShape) (not Inferred(TypeShape))
   - Unresolved (no payload; diagnostic lives in separate table per
     header comment "state == Unresolved iff diagnostics.contains(port_id)")
   - Uninferred (pre-completion transient; absent post-infer)
   Updated §3.1 with the correct PortState shape + the diagnostic-table
   coupling invariant.

3. Behavior variants vs type-level DAG primitive vocabulary were
   conflated. Clarified §5.1 that Behavior is L1 substrate
   (Value/Transform/Branch/Loop/Bind per dag.rs:2600-2606) and is
   distinct from the type-level Node/Conj/Disj/Cardinality/Bit axis
   per feedback_compiler_is_dag_processor.

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

Copy link
Copy Markdown
Contributor Author

Cursor/composer-2 BLOCKING review absorbed — all 3 findings verified valid + fixed in commit d55989d.

Finding 1 (THESIS.md §1505 anchor missing) — verified: grep -n "1505" THESIS.md returns nothing; Shape A/B framing lives in docs/thesis/what-else-falls-out.md §"Two shapes of omni-emission" + normal THESIS.md headings around lines 214-221. Fixed all 3 cites (§3.2 line 57, §8 line 181, §16 line 332) to use the correct anchor per feedback_section_anchors_over_line_numbers.

Finding 2 (PortState misstated) — verified: grep PortState src/v3/compiler/src/infer.rs shows actual variants are Resolved(TypeShape) / Unresolved (no payload) / Uninferred. Header comment lines 24-28 codifies the diagnostic-coupling invariant state == Unresolved iff diagnostics.contains(port_id) — diagnostic lives in the diagnostic table, not in PortState payload. Fixed §3.1 (line 48) to describe the actual substrate boundary including the Uninferred → absent post-infer invariant.

Finding 3 (Behavior vs type-level vocabulary conflation) — verified: src/v3/compiler/src/dag.rs:2600-2606 confirms pub enum Behavior { Value(ValueNode), Transform(TransformNode), Branch(BranchNode), Loop(LoopNode), Bind(BindNode) } — these are L1 substrate-level. Type-level DAG primitives Node/Conj/Disj/Cardinality/Bit per feedback_compiler_is_dag_processor operate at a different axis. Fixed §5.1 (line 108) to (a) cite the correct Behavior variants from substrate.dag mirror, (b) explicitly note the two axes are distinct, (c) prevent conflation in downstream worker briefs.

Thank you for the BLOCKING — these were exactly the kind of substrate-boundary citation drift that L2.5 docs need to be tight on before warm-wolf-698 dispatches workers against the design. Better caught now than after a worker burns cycles on an incorrect substrate model.

— 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: b6c34755 · Trigger: schedule
  • Thinking: 228s wall

BLOCKING (5)

Root Cause

  • docs/design-emit-stage-l25-model.md LanguageSpec authority was declared before resolving the existing v3 substrate home → point the model at the canonical live authority or explicitly ratify a same-document replacement/dissolution path.
  • docs/design-emit-stage-l25-model.md Parity-test byte identity was conflated with verification-gate semantics → keep byte identity only for PB-6 Step 4 parity/fixed-point and describe L4/L5 as typed semantic comparisons.
  • docs/design-emit-stage-l25-model.md Post-infer readiness is asserted over plain Dag instead of modeled as a carrier/witness → introduce or require an inferred-Dag readiness fact, or state the remaining fail-closed runtime gate honestly.
  • docs/design-emit-stage-l25-model.md Parity evidence was planned as a new Rust test without a test-surface dissolution receipt → make it a .dag TestClaim/generated test or name the exact P5 receipt for the hand-Rust test.
  • docs/design-emit-stage-l25-model.md Shape B deferral was represented inside the PB-6 compiler emit substrate → remove Shape B from PB-6 EmissionConfig and keep Shape B in user-program artifact emission lanes.

⚠️ The doc needs the authority paths, verification semantics, stage-boundary type story, P5 parity-test receipt, and Shape B boundary corrected before it can serve as the PB-6 L2.5 model authority.

**Emit is a structural projection from (Dag, LanguageSpec) → (TargetSource ⊕ EmissionDiagnostic), composed via fold over per-target inhabitance facts. NOT a decision engine.**

Per `feedback_lenses_not_passes`: emit is a lens over substrate, not a decision process. Anything emit has to "decide" is a substrate fact the LanguageSpec should declare. The fold is small and mechanical because all the real work is in the substrate facts.

This comment was marked as resolved.

---

## §5 Structural projection (the core)

This comment was marked as resolved.

## §5 Structural projection (the core)

emit composes from these substrate facts via fold:

This comment was marked as resolved.

Comment thread docs/design-emit-stage-l25-model.md Outdated

Per `docs/design-clean-emission-contract.md` (DB-4):

CleanEmissionContract declares 8 typed rule enums per target covering constructive rendering concerns:

This comment was marked as resolved.

| T-Ground-Coercion-Fold | mechanical fold implementation | Gap 13 R3 Grounding Mgr lane | In-flight (PR #1980 ScratchIntExamples retirement; broader work continues) |
| T-Ground-Diagnostic | `EmissionDiagnostic` carrier | Gap 13 R3 Grounding Mgr lane | NOT-STARTED per closure-ledger; brief authored at PR #1216 |
| T-Ground-Lifetime-Analyzer | structural intent derivation | Gap 13 R3 Grounding Mgr lane | In-flight (R2-scope a/b/c impl landed at PR #1206) |
| T-Ground-CrossTarget-Meta | portability requirements meta | Gap 13 R3 Grounding Mgr lane | In-flight (PR #2103 L6 EmissionPathProjection CLOSED) |

This comment was marked as resolved.

…findings

Finding 1 — LanguageSpec authority paths wrong:
- Doc cited `dsl/extdeps/languages/<target>/spec.dag` (does not exist).
- ACTUAL: `LanguageSpec` carrier is DUAL-DECLARED at
  `dsl/std/languages.dag:438` (full schema) AND
  `src/v3/std/emit_model.dag:430` (smaller schema).
- Per-target instance authority is multi-file decomposition
  (`syntax,runtime,errors,primitives,async,emit,imports,naming,lint,types`.dag)
  — NOT a single `spec.dag` per target.
- Fixed §3.2 + §6 table + §12 Q1 framing.
- Operator ratification on canonical carrier choice is now an
  explicit Q1 gate BEFORE PB-6 Step 2 dispatch.

Finding 2 — L4/L5 conflated with byte equality:
- Doc said L4/L5 gates "consume emit output for byte-equality
  assertions". WRONG — L4/L5 are typed semantic verification
  (compile + evaluate + compare results), not byte equality of
  source.
- Byte equality is reserved for PB-6 Step 4 parity (same-target
  emit.rs vs emit.dag) only.
- Fixed §7.2 to clarify the two distinct verification axes.

Finding 3 — Post-infer Dag readiness asserted without witness:
- Doc claimed type-checked composition enforced post-infer
  completion. WRONG — plain `Dag` carries no compile-time witness
  that `state != Uninferred for all ports`.
- Fixed §3.1 + §7.1 + §7.3 to make this a runtime fail-closed
  gate (EmissionDiagnostic::UninferredPortPresent), NOT a
  compile-time guarantee.
- Added §12 Q7 raising the InferredDag-newtype vs runtime-gate
  resolution for operator ratification.

Finding 4 — Parity test as new hand-Rust test without P5 receipt:
- Doc said Step 4 deliverable is `tests/parity_emit_dag_vs_rust_test.rs`
  (NEW). Violates P5 (new hand-Rust test surfaces need dissolution
  receipt).
- Fixed §9 Step 4 to (a) make parity verification a `.dag`
  TestClaim authored via testgen, and (b) explicitly name P5
  dissolution receipt for any required hand-Rust scaffolding
  (transient; dissolves with emit.rs deletion in same PR per
  Step 4 atomic discipline).

Finding 5 — Shape B in PB-6 EmissionConfig substrate:
- Doc proposed `EmissionConfig.target_kind: ShapeAVariant |
  ShapeBVariant` (closed-axis sum). Substrate-modeling error —
  Shape B is user-space artifact emission, NOT compiler-emit
  substrate dispatch axis.
- Fixed §3.3 to declare EmissionConfig Shape-A-only by
  construction.
- Reframed §12 Q4 as RESOLVED (removed from open-ratification
  status; reasoning captured for traceability).

Updated §14 acceptance criteria + §15 authoring sequence to
reflect Q4 RESOLVED + Q7 NEW (operator ratification needed on
Q1, Q2, Q3, Q5, Q6, Q7).

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

Copy link
Copy Markdown
Contributor Author

Codex BLOCKING review (5 findings) absorbed — all valid; fixed in commit 15cae2a.

Finding 1 (LanguageSpec authority paths) — verified via grep -rn "type LanguageSpec" dsl/ src/v3/std/: carrier is DUAL-DECLARED at dsl/std/languages.dag:438 (full schema: identity + syntax + runtime + value semantics + serialization + scaffold + service calls) AND src/v3/std/emit_model.dag:430 (smaller schema: DeclarationRef-shaped). My draft cited non-existent dsl/extdeps/languages/<target>/spec.dag; per-target instance authority is actually multi-file decomposition (syntax,runtime,errors,primitives,async,emit,imports,naming,lint,types.dag per target). Fixed §3.2 + §6 table + §12 Q1. §12 Q1 now explicitly raises canonical-carrier choice as a PRE-Step-2-dispatch operator ratification gate.

Finding 2 (L4/L5 vs byte equality) — fixed §7.2. L4 emit/eval match + L5 cross-target consistency are typed semantic verification (compile + evaluate + compare results), NOT byte equality of source text. Cross-target source bytes differ by construction. Byte equality is reserved for PB-6 Step 4 same-target parity (emit.rs vs emit.dag) only.

Finding 3 (post-infer Dag readiness) — verified that plain Dag carries no compile-time witness; the fn emit(d: Dag, s: LanguageSpec) -> EmissionResult signature doesn't enforce post-infer completion. Fixed §3.1 + §7.1 + §7.3 to model this as a runtime fail-closed gate (EmissionDiagnostic::UninferredPortPresent) rather than compile-time guarantee. Added new §12 Q7 raising InferredDag-newtype-carrier vs runtime-gate resolution for operator ratification. Director-recommend: runtime gate (option b) — carrier-newtype-just-for-witness violates feedback_no_metadata_markers adjacent.

Finding 4 (parity test P5 receipt) — fixed §9 Step 4. Parity verification now authored as a .dag TestClaim (generated test fixture set + TestClaim asserting emit_via_rust(dag, spec) == emit_via_dag(dag, spec) byte-equality on canonical corpus), transient-by-construction. Any hand-Rust scaffolding required for invocation-routing between stage0 emit (reading new emit.dag via Evaluator) and emit.rs (current hand-Rust) bears P5 receipt: "parity_emit_dag_vs_rust_scaffolding — transient; dissolves with emit.rs deletion in same PR per Step 4 atomic discipline".

Finding 5 (Shape B in EmissionConfig) — fixed §3.3 to declare EmissionConfig Shape-A-only by construction (Shape B is user-space artifact emission via standalone .dag programs walking typed values, NOT a compiler-emit substrate dispatch axis). Reframed §12 Q4 as RESOLVED inline (removed from open-ratification status; reasoning captured for traceability that earlier draft conflated user-program-artifact-emission with compiler-target-emission substrate).

Updated §14 acceptance criteria + §15 authoring sequence to reflect Q4 RESOLVED + Q7 NEW. Operator ratification now needed on §12 Q1, Q2, Q3, Q5, Q6, Q7 (6 questions instead of original 6, with Q4 retired + Q7 added).

Both BLOCKING reviews (cursor + codex) addressed via two focused commits (d55989d for cursor's substrate-citation findings; 15cae2a for codex's substrate-modeling findings). Substantive learning — these are exactly the kinds of L2.5 modeling drifts that need to be caught BEFORE workers burn cycles against the design.

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

…3066

Codex inline BLOCKING at line 34 surfaced that the prior fix
(commit 15cae2a) named the wrong per-target authority. The
live v3 authority is:

- LanguageSpec carrier: src/v3/std/emit_model.dag:430
  (also documented in src/v3/SELF_HOSTING.md:592)
- Per-target instances: src/v3/spec/{rust,python,go}.dag
  (each carrying 4 Realization meta-types)
- L1 cross-target markers: src/v3/spec/v3_l1.dag

Legacy bootstrap layer (NOT to consume as PB-6 authority):
- dsl/std/languages.dag:438 (different LanguageSpec schema)
- dsl/extdeps/languages/<target>/*.dag (legacy multi-file
  decomposition: syntax/runtime/errors/primitives/async/emit/
  imports/naming/lint/types per target)

Carrying both forward would constitute a P2 parallel-authority
path that codex BLOCKING explicitly flagged.

Fixed §3.2, §6 table, and §12 Q1:
- §3.2: replaced "DUAL DECLARATION" framing (which would carry
  both layers forward as candidates) with clear "v3 live
  authority" + "legacy bootstrap to dissolve separately" split.
- §6 table T-Ground-LanguageSpec row: updated to cite live v3
  authority; legacy explicitly named as separate dissolution
  lane (not PB-6 scope).
- §12 Q1: reframed from "which carrier is canonical / dual-
  declaration" to "v3 live authority confirmation + legacy as
  separate dissolution lane". Director-recommend explicitly
  cites feedback_lenses_not_passes + INVARIANTS P2.

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

Copy link
Copy Markdown
Contributor Author

Codex INLINE BLOCKING (docs/design-emit-stage-l25-model.md:34, "P2 parallel-authority path" finding) addressed in commit ac48b5f.

The prior fix (15cae2a) framed the LanguageSpec authority as "DUAL DECLARATION TO RESOLVE BEFORE DISPATCH" — which would carry BOTH layers forward as candidates pending operator choice. That framing is itself the P2 parallel-authority risk codex flagged. The right framing is: v3 live authority is canonical, legacy is separate dissolution scope.

Verified via grep:

  • grep -rn "type LanguageSpec" src/v3/ → src/v3/std/emit_model.dag:430 + src/v3/SELF_HOSTING.md:592
  • ls src/v3/spec/ → rust.dag (57754 bytes) + python.dag + go.dag + v3_l1.dag
  • head -30 src/v3/spec/rust.dag confirms 4 Realization meta-types (type realizations + operator realizations + behavior template realizations + dispatch tables) — the live per-target spec authority
  • grep -rn "type LanguageSpec" dsl/ → dsl/std/languages.dag:438 (legacy, different schema)
  • ls dsl/extdeps/languages/rust/ → multi-file decomposition (syntax.dag + runtime.dag + errors.dag + primitives.dag + async.dag + emit.dag + imports.dag + naming.dag + lint.dag + types.dag) — legacy bootstrap

Fixes in commit ac48b5f:

  • §3.2: replaced DUAL-DECLARATION framing with "LIVE V3 AUTHORITY" + "Legacy bootstrap to dissolve separately" split. PB-6 substrate authority is src/v3/std/emit_model.dag:430 (carrier) + src/v3/spec/{rust,python,go}.dag (per-target) + src/v3/spec/v3_l1.dag (L1 markers). Legacy dsl/std/languages.dag + dsl/extdeps/languages/<target>/*.dag is NOT consumed as PB-6 authority.
  • §6 table T-Ground-LanguageSpec row: updated to cite live v3 authority; legacy explicitly named as separate dissolution lane (NOT PB-6 scope).
  • §12 Q1: reframed from "dual-declaration / which carrier canonical" to "v3 live authority confirmation + legacy as separate dissolution lane". Director-recommend now explicitly cites feedback_lenses_not_passes (single substrate authority) + INVARIANTS P2 (no parallel-authority paths).

The P2 parallel-authority risk that codex's BLOCKING flagged is now structurally avoided: PB-6 commits to src/v3/ as the live authority; legacy dsl/std/ + dsl/extdeps/languages/ is a separate dissolution lane (not blocking PB-6 dispatch).

If there are 4 more queued inline BLOCKING findings (per dashboard relay note), I'll address each in sequence as they land. Substantive learning here — initial pass cited wrong path; codex's second-pass review caught the carrier-forward error in the dual-declaration framing.

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

@briansrls

Copy link
Copy Markdown
Contributor Author

Codex INLINE BLOCKING (line:103, "L4/L5 byte-equality contradicts cross-target-equivalence + r3-structure") — verified addressed in commit 15cae2a (pushed before this BLOCKING relay arrived).

The pre-fix HEAD (b6c3475) had this L4/L5 byte-equality framing in §7.2. The fix in 15cae2a §7.2 (currently at line 177 in PR HEAD ac48b5f) now reads:

"R3 Verification Mgr's L4 emit/eval match gates + L5 cross-target consistency gates consume emit output for typed semantic verification (compile the emitted code, evaluate against canonical inputs, compare evaluation results) — NOT byte-equality of source text. Cross-target source bytes differ by construction (Rust vs Python vs Go syntax); the verification is at the semantic/behavioral layer. Byte equality is reserved for PB-6 Step 4 parity verification only — see §9 Step 4: emit.rs hand-Rust output vs emit.dag substrate output for the SAME target. Same-target byte identity is the discriminator that fails for paper-shrink class."

This matches docs/design-cross-target-equivalence.md + docs/r3-structure.md L4/L5 semantic-equivalence framing. Byte equality is preserved for the PB-6 Step 4 same-target parity context only (the discriminator that catches paper-shrink class — relocating Rust to a different file vs genuine .dag substrate substitution).

No additional commit needed for this finding; the relay arrived after the fix was pushed.

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

@briansrls

Copy link
Copy Markdown
Contributor Author

Codex INLINE BLOCKING (line:105, "post-infer Dag type-check distinct from pre-infer Dag — contradicts SELF_HOSTING.md §2.1, leaves stage-boundary invariant convention-level") — verified addressed in commit 15cae2a (pushed before this BLOCKING relay arrived).

Current HEAD (ac48b5f) explicitly acknowledges this in 4 sections:

§3.1 (line 50):

"the post-infer readiness invariant is a RUNTIME fail-closed gate, NOT a compile-time type carrier: the plain Dag type does NOT carry an inferred-Dag witness in its type. Two valid resolution paths surface in §12 Q7 for operator ratification: (a) introduce an InferredDag newtype carrying the witness (compile-time guarantee), or (b) keep plain Dag and have emit fail-closed at runtime with EmissionDiagnostic::UninferredPortPresent if any Uninferred port is encountered at emit-time. The type-checked pipeline-composition signature fn emit(d: Dag, s: LanguageSpec) -> EmissionResult does NOT enforce post-infer completion on its own."

§7.1 (line 169):

"emit depends on Dag whose PortState is post-infer-resolved → output of infer stage (PB-5). Per §3.1 the post-infer readiness is a runtime fail-closed gate... NOT a compile-time type guarantee."

§7.3 (line 181):

"This is enforced as the §3.1 / §7.1 runtime fail-closed gate... NOT a compile-time guarantee — the typed signature fn emit(d: Dag, s: LanguageSpec) -> EmissionResult does not carry a post-infer-completion witness."

§12 Q7 (line 281, NEW per codex BLOCKING):

"Post-infer readiness — carrier-typed witness vs runtime fail-closed gate"
Option (a) InferredDag newtype | Option (b) runtime fail-closed gate
Director-recommend (b) per feedback_no_metadata_markers adjacent (named state observable structurally, not via marker types)
Operator ratification needed before Step 2 dispatch.

The earlier framing was indeed convention-level; the fix makes it honest:

  • Plain Dag signature does not encode the post-infer completion fact in type.
  • Either upgrade to InferredDag carrier (compile-time guarantee) OR explicitly name runtime-gate as the enforcement mechanism (with EmissionDiagnostic::UninferredPortPresent).
  • The choice is now operator-ratification scope.

No additional commit needed; the fix is in HEAD. SELF_HOSTING.md §2.1 contradiction surfaces in the original framing (signature-implies-witness); the fix admits the gap honestly + structures the resolution path.

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

@briansrls

Copy link
Copy Markdown
Contributor Author

Codex INLINE BLOCKING (line:120, "tests/parity_emit_dag_vs_rust_test.rs without P5 receipt — dilutes Pure Bootstrap 0-floor target") — verified addressed in commit 15cae2a (pushed before this BLOCKING relay arrived).

Current HEAD (ac48b5f) §9 Step 4 row (line 206):

"Parity verification authored as .dag TestClaim — generated test fixture set + .dag TestClaim asserting emit_via_rust(dag, spec) == emit_via_dag(dag, spec) byte-equality across canonical corpus. P5 dissolution receipt: this TestClaim is transient-by-construction; it dissolves when emit.rs deletes in the same PR (Step 4 = parity + simultaneous deletion). Any hand-Rust scaffolding required for invocation routing between stage0 emit (reading new emit.dag via Evaluator) and emit.rs (current hand-Rust) bears P5 receipt: parity_emit_dag_vs_rust_scaffolding — transient; dissolves with emit.rs deletion in same PR per Step 4 atomic discipline. EXPECTED_HAND_AUTHORED_NON_TEST shrinks by N entries at PR-merge."

The original framing did dilute the Pure Bootstrap 0-floor target by adding a new hand-Rust test without dissolution receipt. The fix routes through two paths:

  1. Primary path: parity verification is a .dag TestClaim (testgen-emitted from substrate facts per the test-deletion T-α framework I'm holding for operator), not new hand-Rust. This is the (T-α) substrate-fact-subsumed class — no hand-Rust enters the ratchet at all.

  2. Fallback path (if step-4 invocation routing requires hand-Rust scaffolding for stage0-emit-via-Evaluator vs hand-Rust-emit comparison): the scaffolding bears an explicit P5 dissolution receipt naming the Step 4 atomic discipline (parity + simultaneous deletion in same PR) as the dissolution event. The receipt is structural — Step 4 cannot pass without emit.rs deletion → scaffolding cannot persist beyond Step 4 merge.

Pure Bootstrap 0-floor target preserved: any hand-Rust scaffolding is transient-by-construction with named P5 receipt. EXPECTED_HAND_AUTHORED_NON_TEST shrinks (not grows) at PR-merge.

No additional commit needed; fix is in HEAD.

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

@briansrls

Copy link
Copy Markdown
Contributor Author

Codex INLINE BLOCKING (line:149, "ShapeBVariant in EmissionConfig makes Shape B compiler emit target axis — blurs Shape A/B boundary") — verified addressed in commit 15cae2a (pushed before this BLOCKING relay arrived).

Current HEAD (ac48b5f) explicitly addresses this at TWO locations:

§3.3 EmissionConfig (line 68):

"Selects which Shape A target to emit to (Rust / Python / Go for R3). EmissionConfig is Shape-A-only by construction — Shape B is user-space artifact emission (SPICE / English / YAML / Verilog / Terraform), authored by users as standalone .dag programs walking typed values via concat/fold/match. Shape B is NOT a compiler-emit dispatch axis and does NOT belong in PB-6 EmissionConfig surface (per docs/thesis/what-else-falls-out.md §"Two shapes of omni-emission" + r3-structure.md framing). PB-6 emit substrate is compiler-emit only."

§12 Q4 RESOLVED (line 261):

"Q4: Shape B omni-emission deferral boundary (RESOLVED — removed from PB-6 substrate)"
"emit.dag scope = Shape A only (Rust / Python / Go for R3). Shape B does NOT belong in PB-6 EmissionConfig surface... PB-6 compiler-emit substrate has no Shape A/B disambiguation flag — EmissionConfig is Shape-A-only by construction (per §3.3 update + §13 Non-goals)."
"The earlier draft proposed EmissionConfig.target_kind: ShapeAVariant | ShapeBVariant (closed-axis sum) — that was a substrate-modeling error: putting Shape B inside compiler-emit substrate conflates user-program-artifact-emission with compiler-target-emission. Shape B emission is its own lane (post-R3 user-emission work), separate from PB-6."

The earlier draft DID blur the Shape A/B boundary by proposing ShapeBVariant in EmissionConfig. The fix:

  1. Removed ShapeBVariant from EmissionConfig surface entirely; EmissionConfig is Shape-A-only by construction.
  2. Reframed Shape B explicitly as user-space artifact emission (standalone .dag programs walking typed values), NOT compiler-emit substrate.
  3. Q4 retired from open-ratification status; resolution captured for traceability about why the earlier draft was wrong.

The Shape A/B boundary is now structurally preserved at §8.1/§8.2 — Shape A = compiler targets emitting Rust/Python/Go (PB-6 scope); Shape B = user .dag programs (NOT PB-6 scope; separate post-R3 user-emission work).

This was the final queued inline BLOCKING per relay note. All 5 codex findings + 3 cursor findings (8 total across both BLOCKING reviews) addressed across commits d55989d + 15cae2a + ac48b5f. Dashboard re-runs on new HEAD will evaluate the post-fix state.

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

briansrls and others added 4 commits May 14, 2026 06:27
Cursor APPROVE review #3066 noted optional housekeeping: §16
"Surfaces awaiting" still said "Q1-Q6" while §14 + §15 treat Q4
as RESOLVED + Q7 as new ratification target.

Fixed §16 to match §14/§15: Q4 RESOLVED inline, Q7 added.
Internal consistency only; not a thesis/invariant breach.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codex's REQUEST_CHANGES correctly flagged that the prior
Director-recommend (option b — plain Dag + runtime
UninferredPortPresent gate) violated:

- docs/modeling-discipline.md Practice 2 (illegal states
  unrepresentable)
- docs/modeling-discipline.md Practice 6 (API-level
  enforcement over convention)
- feedback_state_space_vs_behavioral_invariants (type
  enforcement > API enforcement)

The prior framing ("feedback_no_metadata_markers adjacent
violation") was wrong — InferredDag is NOT a metadata marker
(those are __is_X string markers); it's structural typed-state.
The reasoning supporting (b) doesn't hold.

Fixed §3.1, §7.1, §7.3 to require typed-state carrier at emit's
signature boundary (post-infer readiness modeled in the type,
not enforced at runtime).

Reframed §12 Q7 from binary (a)/(b) choice (carrier vs runtime)
to a three-way choice on CARRIER SHAPE (newtype / refined-Dag-
via-where-clause / sum-variant). The runtime-gate option is
explicitly retired. New Director-recommend: option (b)
refinement-via-where-clause if refinement substrate at HEAD;
option (a) newtype as transition shape otherwise.

Whatever shape operator picks, the constraint stands: emit's
signature accepts only post-infer typed-state by construction;
the runtime UninferredPortPresent framing is retired.

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

Copy link
Copy Markdown
Contributor Author

Codex REQUEST_CHANGES absorbed — verdict correct, my prior Director-recommend on §12 Q7 was wrong. Fixed in commit 9768875.

The substantive flip:

Prior Director-recommend in §12 Q7 was option (b) — keep plain Dag + runtime UninferredPortPresent gate. The reasoning I gave ("violates feedback_no_metadata_markers adjacent") was wrong. feedback_no_metadata_markers is about __is_X STRING markers ("model concepts structurally in std/") — NOT about typed-state wrappers. InferredDag is structural typed-state, NOT a metadata marker.

The correct discipline references are:

  • docs/modeling-discipline.md Practice 2 (illegal states unrepresentable)
  • docs/modeling-discipline.md Practice 6 (API-level enforcement over convention)
  • feedback_state_space_vs_behavioral_invariants (type enforcement > API enforcement)

All three argue for compile-time typed-state at emit's signature boundary. Codex's REQUEST_CHANGES is correct: locking in runtime-gate would make later correction harder, particularly because this doc is the Step-1 substrate authority for the pipeline-slot declaration.

Fix in commit 9768875:

  • §3.1 (line 50) reframed: "post-infer readiness must be modeled in the type, NOT enforced at runtime"; emit's signature is fn emit(d: InferredDag, s: LanguageSpec) -> EmissionResult

  • §7.1 (line 169) reframed: post-infer readiness modeled via typed-state carrier per Modeling Practices 2 + 6

  • §7.3 (line 181) reframed: stage boundary enforcement is API-level (Practice 6), NOT convention-level

  • §12 Q7 reframed from (a)/(b) binary "carrier vs runtime" to a 3-way choice on CARRIER SHAPE:

    • (a) InferredDag newtype (simple wrapper)
    • (b) refined-Dag via where-clause/predicate (structural refinement; reuses substrate refinement machinery)
    • (c) sum-variant Dag = PreInferDag | InferredDag (closed-axis state machine)

    New Director-recommend: option (b) refinement-via-where-clause if refinement substrate at HEAD (most aligned with feedback_groundedness_gates_lenses + language's first-class structural refinement); option (a) newtype as transition shape if refinement substrate not ready. Option (c) sum-variant is most explicit but has higher cross-codebase refactoring cost.

    Whichever shape operator picks, the constraint stands: emit's signature accepts only post-infer typed-state by construction; the runtime UninferredPortPresent framing is retired.

The doc is now coherent with docs/modeling-discipline.md Practices 2 + 6 + state-space-invariants discipline. Substantive learning: my reach for feedback_no_metadata_markers was pattern-match-without-grep against the wrong feedback entry; the actual feedback that applied (feedback_state_space_vs_behavioral_invariants) argues the OPPOSITE direction. This is the kind of error that BLOCKING reviews are FOR.

— 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: 97688750 · Trigger: schedule
  • Thinking: 254s wall

BLOCKING (1)

Root Cause

  • docs/design-emit-stage-l25-model.md Q7's typed-state reversal was applied to the narrative but not propagated into the concrete pipeline-slot contract → update every emit signature/table row to the chosen typed-state carrier before ratification.

⚠️ One stale concrete signature still preserves the prior stage-boundary bug.

Comment thread docs/design-emit-stage-l25-model.md Outdated
| Step | Deliverable | Owner | Substrate |
|---|---|---|---|
| **Step 1: Model review** | THIS DOC | Director (zesty-bear-812) | docs/design-emit-stage-l25-model.md (this doc) |
| **Step 2: Pipeline slot** | `fn emit(inferred: Dag, spec: LanguageSpec) -> EmissionResult` declared in compiler.dag with `ExternalRealization` body (Rust-backed placeholder pointing to current emit.rs) | R3 Substrate Mgr (warm-wolf-698) — worker dispatched against Director-authored Step 2 brief | compiler.dag refinement |

This comment was marked as resolved.

@briansrls

Copy link
Copy Markdown
Contributor Author

Duplicate of earlier inline BLOCKING relay (cited line:109 here vs line:103 earlier — both reference the same L4/L5 byte-equality finding from codex's first review pass at commit b6c3475). Already addressed in commit 15cae2a; the fix is currently at §7.2 line 177 of HEAD (commit 9768875):

"R3 Verification Mgr's L4 emit/eval match gates + L5 cross-target consistency gates consume emit output for typed semantic verification (compile the emitted code, evaluate against canonical inputs, compare evaluation results) — NOT byte-equality of source text. Cross-target source bytes differ by construction (Rust vs Python vs Go syntax); the verification is at the semantic/behavioral layer. Byte equality is reserved for PB-6 Step 4 parity verification only — see §9 Step 4: emit.rs hand-Rust output vs emit.dag substrate output for the SAME target. Same-target byte identity is the discriminator that fails for paper-shrink class."

This matches docs/design-cross-target-equivalence.md + docs/r3-structure.md L4/L5 semantic-equivalence framing.

No additional commit needed — relay arrived after fix was pushed. Already replied at /issuecomment-4448141132.

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

@briansrls

Copy link
Copy Markdown
Contributor Author

Duplicate relay of P5 receipt finding (cited line:126 here vs line:120 earlier — both reference the same parity-test P5 finding from codex's first review pass at commit b6c3475). Already addressed in commit 15cae2a; the fix is currently at §9 Step 4 line 206 of HEAD (commit 9768875):

"Parity verification authored as .dag TestClaim... P5 dissolution receipt: this TestClaim is transient-by-construction; it dissolves when emit.rs deletes in the same PR (Step 4 = parity + simultaneous deletion). Any hand-Rust scaffolding required for invocation routing... bears P5 receipt: parity_emit_dag_vs_rust_scaffolding — transient; dissolves with emit.rs deletion in same PR per Step 4 atomic discipline."

Already replied at /issuecomment-4448149300.

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

@briansrls

Copy link
Copy Markdown
Contributor Author

Duplicate relay of Shape B finding (cited line:155 here vs line:149 earlier — both reference the same Shape B finding from codex's first review pass at commit b6c3475). Already addressed in commit 15cae2a; the fix is currently at §3.3 line 68 + §12 Q4 RESOLVED line 261 of HEAD (commit 9768875):

§3.3 line 68: "EmissionConfig is Shape-A-only by construction — Shape B is user-space artifact emission... NOT a compiler-emit dispatch axis and does NOT belong in PB-6 EmissionConfig surface"
§12 Q4 line 261: "RESOLVED — removed from PB-6 substrate"

Already replied at /issuecomment-4448151362.

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

…#3066

Codex caught that §9 Step 2 row still showed
`fn emit(inferred: Dag, spec: LanguageSpec) -> EmissionResult`
even though §3.1/§7.1/§7.3/§12 Q7 (post-flip) now require
typed-state carrier (Modeling Practices 2 + 6). Plain `Dag`
signature in Step 2 would leak through to worker brief
authoring + dispatch — convention-level enforcement at the
handoff.

Fixed §9 Step 2 row to use `InferredDag` carrier explicitly,
with note that exact carrier shape (newtype / refined-Dag-via-
where-clause / sum-variant) is gated on §12 Q7 operator
ratification. Whichever shape lands, the signature accepts only
post-infer typed-state by construction.

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

Copy link
Copy Markdown
Contributor Author

Codex INLINE BLOCKING (line:204, "Step 2 still dispatches fn emit(inferred: Dag, ...) even though §3.1/§7/Q7 require InferredDag — Practices 2 and 6 remain convention-level at worker-brief handoff") — substantive finding; fixed in commit 36c2e5c.

The earlier Q7 flip commit (9768875) updated §3.1 / §7.1 / §7.3 / §12 Q7 to require typed-state carrier but missed the §9 Step 2 row signature. The plain Dag in Step 2 would leak through to worker-brief authoring + dispatch — convention-level at the handoff, exactly the failure mode you flagged.

Fix at line 204 (commit 36c2e5c):

"Step 2: Pipeline slot | fn emit(d: InferredDag, spec: LanguageSpec) -> EmissionResult declared in compiler.dag with ExternalRealization body (Rust-backed placeholder pointing to current emit.rs). Exact InferredDag carrier shape gated on §12 Q7 operator ratification — newtype / refined-Dag-via-where-clause / sum-variant Dag = PreInferDag | InferredDag. Whichever shape lands, the signature accepts only post-infer typed-state by construction (Modeling Practice 6 API-level enforcement)."

The Step 2 worker-brief authoring is now structurally gated on Q7 ratification — Director cannot author a Step 2 brief that uses plain Dag signature; the carrier-shape decision must be ratified first.

Substantive learning logged: when a discipline change ripples across a doc, audit ALL signature/contract mentions in subsequent sections, not just the framing sections. The §9 Step 2 row was the worker-handoff contract; missing the update there leaves the discipline as a doc-statement-only with no enforcement at the actual dispatch boundary.

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

@briansrls

Copy link
Copy Markdown
Contributor Author

This is the high-level BLOCKING summary corresponding to the inline finding at §9 Step 2 (line:204). Codex reviewed commit 9768875 and caught the Q7-narrative-vs-Step-2-signature leak. Fixed in commit 36c2e5c (already pushed):

§9 Step 2 row now reads: fn emit(d: InferredDag, spec: LanguageSpec) -> EmissionResult with note that exact carrier shape (newtype / refined-Dag-via-where-clause / sum-variant) is gated on §12 Q7 operator ratification.

Already replied at /issuecomment-4448512454 with the full fix context.

Dashboard re-review on new HEAD (36c2e5c) should retract the REQUEST_CHANGES.

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

briansrls and others added 3 commits May 14, 2026 07:17
…eq count

Two minor doc-hygiene fixes per cursor /api/reviews/11723:

1. Line 1 title: `% Emit Pipeline Stage...` → `# Emit Pipeline Stage...`
   `%` is not a level-1 heading in CommonMark; ATX `#` is the
   correct level-1 heading.

2. Line 159 §6 prereq count: "5 of 7" did not match the 8-row
   table above. Recounted: 6 of 8 prereq rows route through
   Gap 13 R3 Grounding Mgr lane (PB-Substrate co-owned with
   Substrate Mgr; 5 T-Ground sub-lanes exclusively Gap 13);
   remaining 2 (target_source.dag + emit_config.dag) are
   Director-tier substrate-fact-introduction. Enumerated
   explicitly for verifiable correspondence with the table.

Both INVARIANTS P1 ("documentation describes live state")
adjacent — narrow cases (heading hygiene + self-consistent
prose with the table).

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: fa5bdfa3 · Trigger: schedule
  • Thinking: 231s wall

BLOCKING (1)

Root Cause

  • docs/design-emit-stage-l25-model.md §5.3 is keyed to stale design-clean-emission-contract.md framing rather than the live src/v3/std/clean_emission.dag authority → enumerate or mechanically delegate to the live CleanEmissionContract shape before ratification.

⚠️ One live CleanEmissionContract field is missing from the PB-6 model, so the design should be corrected before it becomes the Step 2 authority.

Comment thread docs/design-emit-stage-l25-model.md Outdated

Per `docs/design-clean-emission-contract.md` (DB-4):

CleanEmissionContract declares 8 typed rule enums per target covering constructive rendering concerns:

This comment was marked as resolved.

@briansrls

Copy link
Copy Markdown
Contributor Author

High-level BLOCKING summary of the inline CleanEmissionContract finding (line:126). Codex reviewed commit fa5bdfa; substantive fix already pushed in commit 7bbc6b8.

§5.3 now enumerates the 9 typed fields of CleanEmissionContract directly from live substrate at src/v3/std/clean_emission.dag:13, including variant_payload_field_access (the missing field codex flagged). §5.4 PostEmitVerifier correctly anchored as a FIELD of CleanEmissionContract (not a separate top-level substrate). §12 Q5 retired from open-ratification (enumeration is now live in §5.3, not deferred to Step 2 worker brief).

Already replied at /issuecomment-4448858002 with full fix context.

Dashboard re-review on new HEAD (7bbc6b8) should retract the BLOCKING.

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

briansrls and others added 5 commits May 14, 2026 08:13
#3066

Claude APPROVE non-blocking observations addressed:

1. §3.3 EmissionConfig substrate authority resolved definitively
   via grep at HEAD; emit_config.dag confirmed NEW substrate file
   PB-6 must author. No more deferred TODO.

2. §12 Q7 Director-recommend flipped from (b)/(a) fallback chain
   to (c) sum-variant per `feedback_coproduct_dissolution`
   Practice 2 — (a)/(b) gate at stage boundary but leave parent
   `Dag` as implicit coproduct; (c) makes coproduct explicit.
   Higher refactoring cost absorbed INTO PB-X migration work.
   (a)/(b) framed as fallback if operator scopes (c) out.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Cursor APPROVE_WITH_COMMENTS caught miscite at §12 Q7
director-recommend: "Practice 2 (dissolve coproducts into
coordinates)" — the parenthetical belongs to Practice 4
(Coproduct dissolution), per docs/modeling-discipline.md:26.

Fixed cite to:
- Practice 4 (Coproduct dissolution — dissolve coproducts into
  coordinates; make implicit coordinate-axes structurally
  explicit)
- Practice 2 (illegal states unrepresentable) still cited at
  the end of the paragraph, correctly.

Both practices apply: Practice 4 for making the coproduct
explicit; Practice 2 for the structural-unrepresentability
consequence.

INVARIANTS P1 ("documentation describes live state") satisfied
— internal rubric pointers now match the cited file.

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: 96bc7d18 · Trigger: schedule
  • Thinking: 239s wall

BLOCKING (2)

Root Cause

  • docs/design-emit-stage-l25-model.md §4 treats T-Ground-Diagnostic as future instead of reading the live diagnostics substrate → make src/v3/std/diagnostics.dag the authority and carry its full EmissionDiagnostic shape or route amendments through that file.
  • docs/design-emit-stage-l25-model.md §2/§9 retained the two-argument emit shape after §3.3 introduced a target-selection carrier → choose one target-selection authority and align every emit signature/input list with it.

⚠️ Two substrate-boundary mismatches should be fixed before this document becomes the Step 2 authority.

Comment thread docs/design-emit-stage-l25-model.md Outdated
Fail-closed surface (per `docs/design-emission-model.md:166-190`):

```
type EmissionDiagnostic =

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 EmissionDiagnostic sketch drops the live src/v3/std/diagnostics.dag:176 carrier variants, creating a parallel diagnostic authority and violating INVARIANTS P2 / Modeling Practice 3.

Comment thread docs/design-emit-stage-l25-model.md Outdated
| Step | Deliverable | Owner | Substrate |
|---|---|---|---|
| **Step 1: Model review** | THIS DOC | Director (zesty-bear-812) | docs/design-emit-stage-l25-model.md (this doc) |
| **Step 2: Pipeline slot** | `fn emit(d: InferredDag, spec: LanguageSpec) -> EmissionResult` declared in compiler.dag with `ExternalRealization` body (Rust-backed placeholder pointing to current emit.rs). **Exact `InferredDag` carrier shape gated on §12 Q7 operator ratification** — newtype / refined-`Dag`-via-where-clause / sum-variant `Dag = PreInferDag \| InferredDag`. Whichever shape lands, the signature accepts only post-infer typed-state by construction (Modeling Practice 6 API-level enforcement). Step 2 worker brief authoring routes through Director once Q7 ratified. | R3 Substrate Mgr (warm-wolf-698) — worker dispatched against Director-authored Step 2 brief | compiler.dag refinement |

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 Step 2 signature drops EmissionConfig even though §3.3 declares target selection as a substrate input, splitting target authority and violating INVARIANTS P2 / Modeling Practice 3.

briansrls and others added 2 commits May 14, 2026 08:57
…arity fix

Three doc-hygiene fixes from latest reviewer passes:

1. §1 "This doc does NOT" bullet (cursor APPROVE observation):
   "Touch" → "Own implementation of" with parenthetical
   clarifying PB-Substrate/PB-Bootstrap/PB-Runtime are
   referenced as dependencies, not implemented here.

2. §6 prereq table header + leading note (claude APPROVE
   observation): explicit "AS OF AUTHORING DATE 2026-05-14"
   disclaimer above the table; column header amended to
   "Status at HEAD (as of 2026-05-14)". Operators reading
   post-2026-05-14 should anchor on Gap-tier lane column not
   PR numbers.

3. §9 Step 2 row signature (claude APPROVE observation):
   `fn emit(d: InferredDag, spec)` → `fn emit(d:
   <InferredDagCarrier>, spec)` with explicit placeholder
   note that resolves to one of (a)/(b)/(c) per §12 Q7
   ratification. Avoids premature commitment to "InferredDag"
   as the carrier name when Q7 is unresolved.

All 3 non-blocking; doc remains DRAFT for operator ratification.

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

Codex INLINE BLOCKING surfaced 2 substantive substrate-boundary
mismatches at commit 96bc7d1:

1. §4 treated T-Ground-Diagnostic as future work but the live
   substrate at src/v3/std/diagnostics.dag:201 already declares
   EmissionDiagnostic with 7+ variants (UnderRefined /
   NoInhabitant / ContradictoryUse / OutOfR2Scope /
   LifetimeProgramExtractionPending / FoldNotImplemented /
   MissingEmissionPath + transitional).

   Fix: §4.2 reframed to cite live substrate as the
   carrier-of-truth + carries full variant set forward. §6
   prereq table row updated: T-Ground-Diagnostic is LIVE; what's
   pending is the consumption-side wiring + transitional
   retirement triggers, not the carrier authoring.

2. §3.3 introduced an EmissionConfig 3rd-input but §2 / §9 Step 2
   both use 2-arg emit signature. Substrate-boundary mismatch:
   either drop EmissionConfig or make signature 3-arg.

   Fix: dropped EmissionConfig as redundant. Target selection IS
   via LanguageSpec choice (the per-target spec instances at
   src/v3/spec/{rust,python,go}.dag carry target identity).
   §3.3 reframed: "Target selection IS via LanguageSpec, NOT a
   separate EmissionConfig carrier". §3 header updated to "Two
   input types feed emit". §6 prereq table row marked DROPPED.

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

Copy link
Copy Markdown
Contributor Author

Codex INLINE BLOCKING (2 findings on commit 96bc7d1) — both substantive; fixed in commit 6a9d35c.

Finding 1 (T-Ground-Diagnostic as future vs live):

Verified via grep -n "type EmissionDiagnostic" src/v3/std/diagnostics.dag → line 201. Live substrate authority already declares 7+ variants (UnderRefined / NoInhabitant / ContradictoryUse / OutOfR2Scope / MissingEmissionPath / 2 🟡 TRANSITIONAL: LifetimeProgramExtractionPending + FoldNotImplemented).

Fix:

  • §4.2 reframed to cite src/v3/std/diagnostics.dag:201 as the carrier-of-truth + carry full variant set forward (per INVARIANTS P2 + Modeling Practice 3 facts-carry-forward); preserve 🟡 TRANSITIONAL variants with retirement-trigger documentation.
  • §6 T-Ground-Diagnostic row updated: carrier is LIVE; what's pending is the emission-path CONSUMPTION + 🟡 TRANSITIONAL retirement triggers, not the carrier authoring. Earlier "NOT-STARTED" framing was wrong.

Finding 2 (§2/§9 2-arg vs §3.3 introduces 3rd EmissionConfig input):

The earlier draft §3.3 introduced EmissionConfig as a 3rd input but §2 + §9 Step 2 both use 2-arg signature. Substrate-boundary mismatch.

Fix: dropped EmissionConfig as redundant. Target selection IS via LanguageSpec choice — the per-target spec instances at src/v3/spec/{rust,python,go}.dag carry target identity. Passing rust_spec = emitting to Rust; no separate config carrier needed.

  • §3.3 reframed: "Target selection — IS via LanguageSpec, NOT a separate EmissionConfig carrier"
  • §3 header: "Two input types feed emit" (was "Three")
  • §6 prereq table: emit_config.dag row marked DROPPED with explanation
  • Signature fn emit(d: <InferredDagCarrier>, spec: LanguageSpec) -> EmissionResult now consistent across §2 / §3 / §9

Both substrate-boundary mismatches resolved. The doc no longer drops live diagnostics facts (Practice 3) and no longer introduces a redundant 3rd-input that doesn't appear in §2/§9 signatures.

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

@briansrls

Copy link
Copy Markdown
Contributor Author

Inline version of Finding 1 from the BLOCKING summary at /issuecomment-4448999... (cited line:89 here vs §4 root-cause earlier). Already addressed in commit 6a9d35c:

§4.2 now cites src/v3/std/diagnostics.dag:201 (live substrate) as the carrier-of-truth + carries full 7+ variant set forward (UnderRefined / NoInhabitant / ContradictoryUse / OutOfR2Scope / MissingEmissionPath / 2 🟡 TRANSITIONAL: LifetimeProgramExtractionPending + FoldNotImplemented). No parallel authority — diagnostics.dag is canonical. §6 prereq table row updated accordingly.

Already replied at /issuecomment-4449221143 with full fix context.

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

@briansrls

Copy link
Copy Markdown
Contributor Author

Inline version of Finding 2 from the BLOCKING summary. Cited line:208 here vs §9 Step 2 row in earlier summary. Already addressed in commit 6a9d35c — same direction codex flagged:

  • §3.3 reframed: target selection IS via LanguageSpec choice (per-target spec at src/v3/spec/{rust,python,go}.dag); no separate EmissionConfig carrier.
  • §3 header: "Two input types feed emit" (was "Three").
  • §9 Step 2 signature: fn emit(d: <InferredDagCarrier>, spec: LanguageSpec) -> EmissionResult — consistent with §2 + §3 framing.
  • §6 prereq table: emit_config.dag row marked DROPPED with explanation.

Target authority is now single-source (LanguageSpec carries target identity); no parallel authority split. INVARIANTS P2 + Modeling Practice 3 satisfied.

Already replied at /issuecomment-4449221143 with full fix context.

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

@briansrls
briansrls merged commit b57157b into main May 14, 2026
4 checks passed
briansrls added a commit that referenced this pull request May 14, 2026
…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 added a commit that referenced this pull request May 14, 2026
…trap.md not -zero.md)

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

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

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

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

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

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

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

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

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

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

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>

* WIP: gunbc Director

* docs(r3): fix PB-4 §4.2 diagnostic substrate citation per codex BLOCKING #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>

* docs(r3): drop LowerResult sum-variant per codex INLINE BLOCKING #3077

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>

* docs(r3): typed surface-form references per openai-pro BLOCKING #3077

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>

* docs(r3): claude PR #3077 obs2 — per-phase parity witness for Pass-1 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>

* docs(r3): fix §7.2 DiagnosticSource P2 contradiction per codex REQUEST_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>

* 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 PR #3077 BLOCKING — Q2 symbol-table RESOLVED + Q5 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>

* docs(r3): cursor PR #3077 APPROVE_WITH_COMMENTS — sweep §6 + §16 contradictions

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>

* 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): typed DiagnosticAnchor per openai-pro PR #3077 BLOCKING

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>

---------

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 (#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
…ratification (#3127)

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

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

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

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

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

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

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

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

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

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

INVARIANTS P1 — documentation must not overstate authority cites.

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

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

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

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

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

Same discipline as PR #3126 commit bdff8c5.

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

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

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

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

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

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

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

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

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

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

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

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

Codex REQUEST_CHANGES (sha b881de2) with 2 substantive findings:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

---------

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

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

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

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

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

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

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

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

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

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

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

INVARIANTS P1 — documentation must not overstate authority cites.

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

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

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

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

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

Same discipline as PR #3126 commit bdff8c5.

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

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

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

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

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

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

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

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

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

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

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

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

Codex REQUEST_CHANGES (sha b881de2) with 2 substantive findings:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Read as contradictory by reviewers. Need one coherent story.

Fix: §7.1 reframed with two distinct axes explicit:

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

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

Both claims coherent on the axis split; not contradictory.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Phantom addition violated INVARIANTS P1 live-state honesty.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Fix: added classifications + dissolution triggers:

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

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

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

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

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

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

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

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

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

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

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

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

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

* WIP: gunbc Director

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

* WIP: gunbc Director

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

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

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

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

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

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

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

---------

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

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

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

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

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

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

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

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

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

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

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

INVARIANTS P1 — documentation must not overstate authority cites.

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

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

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

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

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

Same discipline as PR #3126 commit bdff8c5.

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

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

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

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

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

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

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

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

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

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

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

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

Codex REQUEST_CHANGES (sha b881de2) with 2 substantive findings:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Read as contradictory by reviewers. Need one coherent story.

Fix: §7.1 reframed with two distinct axes explicit:

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

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

Both claims coherent on the axis split; not contradictory.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Phantom addition violated INVARIANTS P1 live-state honesty.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Fix: added classifications + dissolution triggers:

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

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

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

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

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

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

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

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

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

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

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

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

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

* WIP: gunbc Director

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

* WIP: gunbc Director

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

---------

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

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

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

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

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

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

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

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

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

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

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

INVARIANTS P1 — documentation must not overstate authority cites.

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

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

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

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

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

Same discipline as PR #3126 commit bdff8c500.

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

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

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

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

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

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

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

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

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

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

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

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

Codex REQUEST_CHANGES (sha b881de23) with 2 substantive findings:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Read as contradictory by reviewers. Need one coherent story.

Fix: §7.1 reframed with two distinct axes explicit:

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

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

Both claims coherent on the axis split; not contradictory.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Phantom addition violated INVARIANTS P1 live-state honesty.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Fix: added classifications + dissolution triggers:

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

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

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

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

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

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

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

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

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

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

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

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

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

* WIP: gunbc Director

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

* WIP: gunbc Director

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

* docs(r3): codex PR #3127 BLOCKING (sha 8e682eef) — §3.1 source identity + §4.2 live-vs-proposed clarity

PR #3127 was merged at 02:04:22Z but codex's later review on sha 8e682eef
caught two findings that still live in main. Both addressed in this PR
(PR #3140) since the tokenize doc lives on main and this is the open
post-merge cleanup branch.

Finding 1 — §3.1 source-identity drop:
Earlier draft framed tokenize input as bare `String → List<Token>`. That
contradicts live `tokenize_generated.rs:96`:
  pub fn tokenize(source: &str, file: &str) -> Result<Vec<Token>, Diagnostic>
The `file` parameter is load-bearing because `SourceSpan` requires a
file/source-id field for byte ranges to be attributable; without it the
Token + Diagnostic span fields would have to fabricate source-id at the
pipeline boundary (P3 fail-closed violation). §3.1 now ratifies the live
two-input shape:
- `source: String` — UTF-8 source text (primitive).
- `file: SourceFileId` — source-identity carrier; Step 2 brief ratifies
  the appropriate `.dag` shape (NonEmptyStr newtype or richer sum if
  multiple source-class kinds).

Finding 2 — §4.2 live-vs-proposed blur:
Prior framing said "TokenizeDiagnostic (substrate extension per Decision
2.B)" without making clear that this is a PROPOSED per-stage carrier,
not the live one. The live carrier at `diagnostics.dag:150` is generic
`Diagnostic { kind: AnyDiagnosticKind, ... }` with kind sum at `:139-142`
discriminating CompilerKind vs LensInstanceKind; tokenize emits today
via `Diagnostic::TokenizerError`-shaped sites carrying
`kind: CompilerKind(...)`. §4.2 heading now reads "PROPOSED — NOT yet
live" + a codex-finding callout explicitly distinguishing the live
carrier from the proposed per-stage refinement + Q7 status DONE.

Both fixes preserve the e9739ea4f 🟡 SCAFFOLD coproduct receipt that
was already addressing codex sha 887c69671 Finding 2.

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

* docs(r3): cursor PR #3127 INLINE BLOCKING line:121 — §4.3 + §9 Step 2 signature sweep

Cursor inline at sha 8e682eef line:121 (the §4.3 Step 2 signature site)
caught the same source-identity drop my §3.1 fix already addressed at the
input-type framing — but two companion sites still had the single-input
signature:
- §4.3 line:151 Step 2 signature recap
- §9 Step 2 row (4-step migration table)

Both now read:
  fn tokenize(source: String, file: SourceFileId) -> Result<List<Token>, TokenizeDiagnostic>

matching the §3.1 source-identity discipline + live `tokenize_generated.rs:96`
`pub fn tokenize(source: &str, file: &str)` shape.

Same `feedback_discipline_change_audit_all_contract_mentions` recurrence
— my Finding 1 fix at §3.1 (commit 18af49fad) didn't sweep the §4.3 + §9
contract-signature restatements.

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

* docs(r3): cursor PR #3127 INLINE BLOCKING line:166 — §6 row TokenizeDiagnostic LIVE/PROPOSED clarity

Cursor inline caught ambiguity in the §6 prereq-table row for
"TokenizeDiagnostic substrate extension." Old wording in column 4 read
"Carrier LIVE; per-stage variant authoring NEW" which could be parsed
as "TokenizeDiagnostic carrier itself is LIVE" — but no `type
TokenizeDiagnostic` exists in `dsl/std/` or `src/v3/std/`. Only the
generic `type Diagnostic` at `diagnostics.dag:150` is live.

Cursor's secondary claim that "line 150 is EmissionDiagnostic receipt
prose" is INCORRECT — verified via grep + read: `diagnostics.dag:150`
is the `type Diagnostic { kind: AnyDiagnosticKind, ... }` declaration
header. `type EmissionDiagnostic` lives separately at `diagnostics.dag:201`.
The §6 row's citation of `:150` for the underlying Diagnostic carrier
is correct.

But the ambiguity-in-wording finding stands. Reframed the row:
- Column 1: explicitly "PROPOSED — no `type TokenizeDiagnostic` exists yet"
- Column 2: clarifies the LIVE underlying carrier is `type Diagnostic`
  with `kind: AnyDiagnosticKind` sum at `:139-142`; cites Q7 ratification
  done timestamp.
- Column 4: explicit "Underlying Diagnostic carrier LIVE at HEAD;
  per-stage TokenizeDiagnostic variant authoring is NEW work, NOT live
  substrate" with cursor-finding callout.

Consistent with §4.2's "PROPOSED — NOT yet live" framing from commit
18af49fad.

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

* docs(r3): cursor PR #3141 INLINE BLOCKING line:68 — §2 structural-signature sweep

Cursor inline caught §2 still framing tokenize structural signature as
`String → List<Token>` — single bare-string input, no source-identity,
no Result-sum failure shape — while §3.1 + §4.3 + §9 Step 2 row all
ratify the live two-input + fail-fast Result-sum shape.

Same `feedback_discipline_change_audit_all_contract_mentions` recurrence
that's been compounding across this fix-forward sequence: each finding
fix needs a doc-wide signature-restatement sweep, not just the §-local
sentence.

Resolution: §2 structural-shape sentence now reads
  `(String, SourceFileId) → Result<List<Token>, TokenizeDiagnostic>`
matching §3.1 (source-identity), §4.3 (Result-sum cross-stage
discriminator), §9 Step 2 row, and live `tokenize_generated.rs:96`
`pub fn tokenize(source: &str, file: &str) -> Result<Vec<Token>,
Diagnostic>`. Cross-refs added to §3.1 + §4.3 to make the discipline
visible at the high-level framing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(r3): cursor PR #3141 INLINE BLOCKING line:73 — replace invented SourceFileId with live FilePath

Cursor caught me inventing `SourceFileId` as the Step 2 boundary type
without a live `.dag` declaration. Verified via grep:
  grep -rn '^type SourceFileId' dsl/ src/v3/
returns empty. Same `feedback_grep_substrate_before_naming_ratification`
family error as the earlier `ScannerCharClass` miss — naming a substrate
carrier without grep-verification.

Live carrier already exists at `dsl/std/types.dag:276`:
  type FilePath = String where non_empty

referenced by `type SourceSpan { file: FilePath, ... }` at
`dsl/std/types.dag:293`. So source identity flows through every Token +
Diagnostic span field via the live `FilePath` carrier — no new carrier
authoring needed at Step 2.

Edits:
- §2 structural-signature: `(String, SourceFileId)` → `(String, FilePath)`
- §3.1 source-identity bullet: replaces fictional SourceFileId with the
  live `FilePath` declaration cite (dsl/std/types.dag:276), points out
  that `SourceSpan.file` already references this same carrier, and adds
  a cursor-finding callout naming the failure mode.
- §4.3 + §9 Step 2 signature restatements: `file: SourceFileId` →
  `file: FilePath`.

Single substrate authority (INVARIANTS P1/P2) restored: FilePath is the
one carrier for source identity across SourceSpan + tokenize input +
Token construction.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request May 15, 2026
…afts) (#3139)

* docs(r3): rust retirement catalogue + emit.rs modeling doc (format-validation drafts)

Per operator 2026-05-15 directive — replace SG-0 file-path ratchet (which
rewards file-path manipulation / paper-shrink) with a substrate-authority
planning artifact. Focus on actual `.dag` substrate growth, not ratchet
file-list shrinkage.

Two docs:

(1) `docs/r3-rust-retirement-catalogue.md` (159 lines)
- Framing: explicit anti-paper-shrink stance citing
  `feedback_template_relocation_paper_shrink_discriminator` (cycles 4/5/6
  reverts at PR #3059)
- Format spec for per-entry catalogue: Role / Public surface / Inputs /
  Calls into / Called by / Existing `.dag` substrate / Retirement target /
  Replacement plan (R1=substrate, R2=consumer-reads-substrate-not-template,
  R3=parity invariant — semantic NOT textual) / Anti-paper-shrink check /
  Phase 1-5 / Substantive retirement risks
- 5-phase retirement plan ordered cheapest-first:
  Phase 1: hand-Rust monotonicity invariant (foreclose growth)
  Phase 2: test harness layer (122 → 1-3 via .dag TestClaim)
  Phase 3: lens-as-Rust (7-10 → 0 via data lens_X: Lens<C> + fold_lens)
  Phase 4: substrate-mirror generation (5-8 → 0 via regen reads
           substrate.dag)
  Phase 5: pipeline-stage retirement (12-15 → meta-circular bootstrap)
- One worked example entry: src/v3/compiler/src/emit.rs (3,992 lines)
  with 4 substantive retirement risks flagged
- 5 open format questions for operator before scaling to remaining ~176
  entries

(2) `docs/r3-retirement-modeling-emit-rs.md` (310 lines)
- Per-file modeling doc; first instance of a series (one per Rust file)
- §1 What emit.rs does (4 internal layers identified)
- §2 Reference pattern (tokenize.dag) — the proven `.dag`-drives-retirement
  example
- §3 6-layer identification ordered by tractability (Layer 1 dispatcher =
  most tractable; Layer 6 = whole-file retirement)
- §4 Layer 1 (dispatcher) FULLY MODELED:
  * 4 new substrate carriers in src/v3/std/emit_model.dag: EmitTarget,
    EmitMode, EmittedSource, EmitTargetDispatchRow
  * 1 data value: emit_target_dispatch_table
  * 3 pure functions: emit_with_mode, emit, emit_module
  * Codegen driver outline: new regen_emit_dispatcher.rs following
    regen_tokenize.rs pattern
  * Parity verification: SEMANTIC (m1_3/m1_4 integration tests pass
    unchanged) NOT TEXTUAL (no source-clone)
- §5 Sketches for Layers 2-N
- §6 4 open questions about .dag substrate-language features needed
- §7 Substantive retirement risks (paper-shrink discriminators)
- §8 What Layer 1 demonstrates (proof-of-pattern for emit translation)

Neither doc proposes changing the ratchet now — that's separate operator
direction. These are planning artifacts for the substantive retirement
work, not enforcement bridges.

Tokenize/parse pipeline stages are already fully substrate-driven (the
proof-of-concept). Lower/infer/emit have L2.5 design docs (PR #3066,
#3077, #3085, #3126 just merged) but no executable `.dag` substrate yet —
the modeling doc series identifies the smallest tractable layer per file
to begin substantive migration.

Co-authored-by: Brian (operator briansrls) — directive 2026-05-15

* docs(r3-catalogue): restructure per claude APPROVE-exploratory PR #3139 — move 5-phase plan above format spec (single authority for Phase enum)

claude APPROVE on commit 458b08d (PR #3139, 2026-05-15T02:14:43Z) flagged a
non-blocking exploratory note: "the catalogue's Phase enum is defined inside
the per-entry format spec block, but the 5-phase plan section at the bottom
is the canonical authority — if this doc lives long, consider moving the
phase definitions above the format spec so the format references rather than
redefines them."

Applied — the doc now has the 5-phase plan section FIRST, with full
definitions, and the format spec section references Phase numbers without
duplicating definitions. Eliminates the dual-authority problem the
exploratory note identified.

Section order (post-fix):
- §"5-phase plan (canonical authority for Phase enum referenced below)"
- §"Format spec (per entry — references Phase numbers from §"5-phase plan"
  above)"
- §"Catalogue" (worked example: emit.rs)
- §"(Remaining ~176 entries — to be filled per format-ratified spec)"
- §"Open questions for operator before format is ratified"

The format spec's Phase field now reads: "Phase: one of Phase 1–5 per
§"5-phase plan" above. (Definitions are NOT duplicated here — the §"5-phase
plan" section is the single authority.)"

No content changes beyond structure; doc is 154 lines (down 5 from
de-duplication of the Phase definitions).

* docs(r3): add Path B tokenize/parse brief set (9 briefs, no workarounds)

Per operator directive 2026-05-15 — "could we try to do path B for tokenize/
parse (NO workarounds) now — i'd like to spawn workers under you directly".

Planning doc enumerating the 9 briefs needed for true 100% .dag retirement
of tokenize + parse including codegen drivers. Workers spawn directly under
deep-wolf-155 (PM) per operator; no Director/Mgr layer for this lane.

Dispatch graph:
- Phase 0 (parallel, no deps): Briefs 1-3 substrate-language gaps
  - Brief 1: generic methods on FreeMonoid<T> (non-endomorphic map + per-method type params; named gap at dsl/std/algebra.dag:387-393)
  - Brief 2: format(template, args) + Int/Char/Bool → String primitives
  - Brief 3: char-class structural completion (finish in-progress scaffold at tokenize.dag:23-58)
- Phase 1 (parallel, no deps on Phase 0): Briefs 4-6 host effects + bridge
  - Brief 4: FileReadEffect + FileWriteEffect (bundle)
  - Brief 5: ProcessSpawnEffect (for rustfmt)
  - Brief 6: compile_to_dag FFI bridge — operator decision point (FFI vs self-hosted)
- Phase 2 (depends on Phases 0+1): Briefs 7-9 driver authoring
  - Brief 7: tokenize_codegen.dag (retires regen_tokenize.rs 1,186 lines)
  - Brief 8: parse_tables_codegen.dag (retires regen_parse_tables_emit.rs 1,284 lines)
  - Brief 9: parse_codegen.dag (retires regen_parse_emit.rs 124 lines)

Cumulative: 6-12 months optimistic, 12-18 realistic. Substrate-language work
in Briefs 1-6 unblocks Phase 2/3/5 broader retirement paths beyond
tokenize/parse alone.

5 open questions for operator at end of doc:
1. Brief 6 FFI vs self-hosted architectural choice
2. Spawn cadence (parallel vs sequential)
3. Test harness scope (in or out of this brief set)
4. Substrate-language work attribution to Phase 2/3/5
5. Worker parallelism cap (3-4 in flight realistic)

Anti-paper-shrink discriminator applies to all 9 briefs: substrate-growth
PR-by-PR is the receipt, not file-path shrinkage.

* docs(briefs): add Path B Phase 0 worker briefs (1-3) — individual files for dispatched workers

Workers witty-moth-725 (Brief 1), sunny-tern-495 (Brief 2), bright-swift-668
(Brief 3) auto-spawned under deep-wolf-155 per operator directive. The work-
item titles were truncated and didn't carry full brief content; this commit
provides the canonical single-file brief per worker.

- docs/briefs/r3-path-b-brief-1-freemonoid-generic-methods.md
  Worker: witty-moth-725
  Gap: dsl/std/algebra.dag:387-393 (FreeMonoid<T>.map endomorphic only)
  Estimated effort: 2-6 months substrate-language work

- docs/briefs/r3-path-b-brief-2-string-templating-conversions.md
  Worker: sunny-tern-495
  Gap: no format(template, args) + verify Int/Char/Bool → String primitives
  Estimated effort: 1-3 months

- docs/briefs/r3-path-b-brief-3-char-class-structural.md
  Worker: bright-swift-668
  Gap: tokenize.dag:23-58 named scaffold (char_in_class NYI for structural execution)
  Estimated effort: 1-2 months

Each brief:
- Investigation-first (Phase A) — surface findings to deep-wolf-155 before authoring
- Concrete deliverables + acceptance criteria (substrate-fact-at-HEAD)
- Anti-paper-shrink discriminator (substrate growth, not file-path manipulation)
- Coordination protocol: direct dashboard-message to deep-wolf-155, no Director/Mgr layer
- PR title prefix r3-path-b-brief-N for traceability

* docs(r3): address codex + briansrls BLOCKING PR #3139 — align catalogue with 0-floor target + dissolve EmitTarget closed enum into LanguageSpec open registry

Two valid BLOCKING findings:

(1) codex REQUEST_CHANGES (catalogue.md:31, :52, :55) — "irreducible 10-15
    file seed" + "Irreducible bootstrap seed (cannot retire)" framings
    CONTRADICTED `docs/design-pure-bootstrap-zero.md` (LIVE 2026-04-25
    cascade promotion) which establishes the in-tree floor as ZERO.
    Authoritative text:
    - line 41: "Goal: zero hand-authored files in v3's source tree."
    - line 95: "the in-tree floor target is 0 regardless of which N=0
      resolution lands"
    - line 191: "If first-time bootstrap (N=0) resolution requires
      hand-Rust in v3's source tree — STOP. The resolution is supposed
      to live outside v3's source tree (install script, gunbc-runtime
      crate, or rustc macro)."

(2) briansrls INLINE BLOCKING (modeling-emit-rs.md:125) — proposed
    `type EmitTarget = Go | Rust | Python` closed sum REINTRODUCED a
    target roster that the live `src/v3/std/emit_model.dag` header
    (lines 8-16) explicitly dissolves via LanguageSpec references:
    "Adding a new shared target is a pure spec-file change — drop a
    `<target>.dag` with a LanguageSpec data item and reference it from
    each realization. No compiler enum roster to edit."

Fixes:

Catalogue (docs/r3-rust-retirement-catalogue.md):
- §"5-phase plan" end-state: replaced "irreducible 10-15 file seed"
  with 0-floor target. Files that look irreducible (bootstrap drivers
  etc.) retire by MOVING OUT-OF-TREE per design-pure-bootstrap-zero.md
  N=0 resolution paths (install script / gunbc-runtime crate / rustc
  macro), NOT by accepting a permanent in-tree residual.
- §"Format spec" per-entry "Retirement target" options: replaced
  "Irreducible bootstrap seed (cannot retire; document why)" with
  "Moved out-of-tree". Added explicit (N.B.) citing codex BLOCKING +
  design-pure-bootstrap-zero.md line 191: planning artifact does NOT
  have authority to introduce permanent in-tree carve-outs against the
  live 0-floor design.

Modeling doc (docs/r3-retirement-modeling-emit-rs.md):
- §4.1 substrate carriers: retracted `type EmitTarget = Go | Rust |
  Python` closed sum. Replaced `EmittedSource.target: EmitTarget` with
  `EmittedSource.language: DeclarationRef` matching the
  `TypeRealization.language: DeclarationRef` pattern at
  emit_model.dag:18. Removed `EmitTargetDispatchRow` separate roster
  carrier — LanguageSpec registry IS the roster.
- §4.2/§4.3: dispatch reads LanguageSpec declarations from
  src/v3/spec/*.dag directly via declaration-namespace walk; functions
  now take `language: DeclarationRef` parameter.
- §4.4 codegen driver: GENERATED Rust uses open-registry pattern too —
  no hardcoded `match EmitTarget { Go => ..., Rust => ..., Python => ... }`
  in emitted code; dispatches via DeclarationId lookup against the
  live LanguageSpec registry.
- §6 open question #2: variant-arm exhaustiveness check replaced with
  declaration-namespace-walk-by-type-tag (open-registry concern).
- §7 substantive retirement risks: paper-shrink discriminator updated
  (no closed enum reintroduction in generated Rust). Cross-target
  convenience wrappers collapse to ONE `emit_text(dag, language)`
  parameterized function.

EmitMode = Program | Module stays as a closed sum (intentionally
bounded; structurally distinct from target-roster concern).

* docs(r3): address briansrls BLOCKING PR #3139 at catalogue.md:21 — expand Phase 1 monotonicity invariant to full hand-Rust surface (include src/v3/compiler/tests/**)

briansrls inline BLOCKING at 2026-05-15T02:48:45Z flagged that Phase 1
scoped only src/v3/compiler/src/, leaving Rust tests outside the
net-shrink gate even though INVARIANTS.md P5 + T-PB-B explicitly
include Rust tests in the hand-Rust surface.

Verified at INVARIANTS.md:323 (Dispatch-Discipline Mechanisms (b)):
  "Hand-Rust includes Rust tests (src/v3/compiler/tests/**) — these
   are the T-PB-B test subset of the SG-0 census; the gate applies
   the same way it applies to T-PB-A non-test files."

Fix: Phase 1 monotonicity invariant now scopes the FULL hand-Rust
surface (src + tests). Eliminates the loophole where gate-closure
PRs adding Rust tests would skirt the invariant — which is exactly
the growth pattern observed in the SG-0 trajectory data (TEST array
went 122 → 130 → 131 across recent gate-closure PRs).

* docs(r3): M2 / class-5 deferral debt survey (operator-requested 2026-05-15)

Per operator directive: "Can we please find all instances of this happening
in this project - i want to attack one of these problems specifically so we
can gather some confidence."

Survey enumerates the M2-deferred / class-5-blocked work in the project:

Quantitative scope:
- 119 references to "class-5" across docs/ + src/v3/ + dsl/
- 61 citations naming class-5 as a blocker / dissolution trigger
- 161 ArrowBody::Unparsed std fn bodies (58% of 276 total)
- 1 dedicated design doc (docs/design-m2-feature-parity.md, status "Design
  ready for implementer review") sitting unimplemented

Enumeration:
1. M2 Feature Parity (DB-9 through DB-13, design doc ready):
   - DB-9: Mutual recursion lowering (L)
   - DB-10: data value semantics (S) — RECOMMENDED ATTACK POINT
   - DB-11: where refinement predicates (M)
   - DB-12: surface generics (S)
   - DB-13: Disj dotted-path (S)
2. Class-5 grammar gaps (substrate-language sub-program):
   - #1: Brace-bodied fn on .dag files (161 Unparsed std fns)
   - #2: Record literals inside data bodies
   - #3: Lens-fold prereq
   - #4: Variant-constructor expressions
   - #5: Dimension<C> data declarations (blocked on #2)
   - #6: Name rosters
3. Hand-Rust trampolines that exist BECAUSE class-5 isn't closed
4. Downstream symptoms (R3 retirement stalls, lens trampolines, etc.)

Recommendation: DB-10 (data value semantics) as confidence-builder:
- Smallest (size S per doc)
- Substrate carrier already exists (Declaration.value_body at dag.rs:122)
- Gap is downstream consumers, not substrate-shape change
- Closes class-5 sub-gap #2 + unblocks dimension framework + cost-lens
  trampoline retirement
- Estimated 1-2 weeks if design is accurate
- Demonstrates "we can close M2 deferrals" pattern

Alternative: class-5 brace-body parse for .dag files (bigger lever, more
invasive; coordinates with Brief 3 worker bright-swift-668).

* docs(r3-catalogue): clean up stale 'irreducible bootstrap seed' reference in Open Questions §5 (briansrls BLOCKING PR #3139 follow-through at catalogue.md:163)

briansrls BLOCKING at catalogue.md:31 about the "irreducible 10-15 file
seed" framing was already addressed in commit 6bafd12 (relay arrived
after fix per dashboard typical relay-after-fix pattern). However, a
stale reference to "irreducible bootstrap seed" remained at line 163
in the Open Questions section — reframed as "move out-of-tree per
design-pure-bootstrap-zero.md N=0 resolution paths" with explicit
no-permanent-residual disclaimer.

The retraction at lines 31-38 + §"Format spec" (N.B.) at line 64
remains the canonical retraction text per the prior commit.

* docs(briefs): add Path B Brief 4 — DB-10 data value semantics (M2/class-5 confidence-builder attack point)

Per operator directive 2026-05-15 — "lets attack DB-10 for confidence,
give it to one of the existing path B brief members".

Brief 4 dispatches DB-10 (data value semantics, M2 feature parity item 3a.2)
to witty-moth-725 — they closed Brief 1 cleanly (PR #3142 promoted to
ready) and are available for new substrate-language work.

Authoritative design at docs/design-m2-feature-parity.md §DB-10 (lines
20-71); doc carries "Design ready for implementer review" status since
authoring. This is the FIRST attack against the M2 / class-5 deferral
pit per the survey at docs/r3-m2-class-5-deferral-survey.md.

Scope:
- Phase A: verify design-doc cited locations (dag.rs:122, lower.rs:1404,
  test_3a2_data_field_access_resolves_statically test ratchet) against
  HEAD; surface drift findings to deep-wolf-155
- Phase B: land 3 consumers per design — Dag::data_value_at accessor +
  SurfaceExpr::Var fallback for scalar inlining + lower_field_path_expr
  walks ValueBody::Structural for static field access
- Phase C: test fixture demonstrating data answer = 42 + answer + 1
  emits 42 + 1 inline across all 3 target languages

Architectural commitment honored (per design + PR #496 2026-04-17):
inlining at LOWERING, not emission. Load-bearing per locked test ratchet.
Emission-time inlining REJECTED.

Coordination: parallel to PR #3142 merge (Brief 1 closure); separate
branch; report findings directly to deep-wolf-155 (no Director/Mgr
layer). Coordinate with sunny-tern-495 (Brief 2) + bright-swift-668
(Brief 3) only if substrate work overlaps.

Anti-paper-shrink discriminator: locked test asserts no FieldProject
Transform exists in the lowered DAG for data-resolved field accesses;
that ratchet catches trampoline-style workarounds.

Estimated effort: 1-2 weeks if design doc is accurate.

* docs(r3): retract stale 'M2 not landed' framing — DB-10/12/13 verified LANDED at HEAD 2026-05-15

Per gentle-bat-24 Brief 4 Phase A finding (DB-10 substrate already
implemented at HEAD with `Dag::data_value_at` at dag.rs:4310 +
lower.rs:8489+/8642+/9125+ + passing test at m2_feature_parity_test.rs:771)
+ subsequent verification of DB-12/DB-13 status amendments in PR #496 against
HEAD test names:

DB-10: LANDED
DB-12: LANDED (parse_generated.rs:927; m2_feature_parity_test.rs:90-156)
DB-13: LANDED (lower.rs:3375; m2_feature_parity_test.rs:163-208)
DB-9 + DB-11: HEAD landed-state NOT YET AUDITED; may also be silently landed

Sites updated:
- docs/r3-m2-class-5-deferral-survey.md: M2 feature parity table reframed
  with cited HEAD evidence per DB; explicit retraction of "no DB item has
  landed yet" claim; active deferral pits shrink to DB-9 + DB-11 (pending
  audit) plus class-5 sub-gaps which remain genuinely deferred per Brief 3
  findings
- docs/design-m2-feature-parity.md: top-level Status line updated from
  "Design ready for implementer review" to "3 of 4 LANDED" with per-DB
  cited HEAD evidence; explicit advisory that workers should audit HEAD
  state before authoring implementation against this doc

Residual M2 work for the 3 LANDED items: emission-test-coverage gap for
DB-12 + DB-13 (design §Acceptance promises 3-target render verification;
current tests check compile + lower only). Small follow-up scope; not
pit-shaped.

The "M2 deferral pit" framing was substantially wrong as initially
described — much of M2 has been silently landing. The class-5 sub-gaps
remain genuinely deferred per Brief 3's bright-swift-668 investigation
(brace-body fn parse on .dag files).

Per `feedback_corrections_must_grep_verify_source` — this is the
canonical lesson: design docs drift; verify against HEAD before
authoring against them.

* docs(r3): address codex BLOCKING PR #3139 (review #12458) — retract String-typed EmitDispatchError + retract Brief 6 FFI bridge as deliverable path

Two findings, both valid:

(1) modeling-emit-rs.md:203 — proposed `type EmitDispatchError { language:
DeclarationRef, detail: String }` as 🟡 SCAFFOLD. RETRACTED. INVARIANTS P3 +
docs/modeling-discipline.md Practice 1 forbid String-typed diagnostic channels
at the substrate-API level. SCAFFOLD-with-String at the API level is still
a String-API at HEAD; the scaffold marker doesn't excuse the typed-carrier
requirement.

Fix: defer the EmitDispatchError shape entirely until per-language typed error
carriers land (Brief 7+). Dispatcher signature stays Result<EmittedSource, ???>
with ??? as forward-reference. Workers attempting Brief 7+ surface back if
the error-carrier shape becomes load-bearing before per-language errors exist
— substantive substrate-language question, not papered over with String channel.

(2) brief-set.md:206 — Brief 6 presented an "FFI bridge" option (a) as a
deliverable path. The brief text itself admitted "does not retire the Rust
compile_to_dag function itself" — that's a bridge preserving hand-Rust
compiler authority, NOT retirement. Operator's NO WORKAROUNDS stance +
INVARIANTS P5 forbid FFI as deliverable path. The brief currently muddled
this; codex correctly flagged that the wording would send a worker to execute
the wrong work.

Fix: Brief 6 reframed as SCOPE MARKER ONLY (Phase 5 program, NOT dispatchable
within this brief set). Recommendation surfaced to operator: declare Phase 5
/ meta-circular bootstrap as separate program from Path B; tokenize/parse
codegen-driver retirements (Briefs 7-9) are downstream of Phase 5 and not
landable until self-hosted compile_to_dag lands. Honest framing: forcing
Briefs 7-9 to land before Phase 5 via FFI bridges produces paper-shrink, not
retirement.

Sites updated:
- modeling-emit-rs.md §4.3 EmitDispatchError block: explicit RETRACTION text;
  signature now Result<EmittedSource, ???> with forward-reference framing
- brief-set.md §"Brief 6 — Meta-circular: compile_to_dag Foreign-Function Bridge"
  retitled to "self-hosted compile_to_dag (Phase 5 scope expansion)" + scope
  reframed as SCOPE MARKER ONLY
- brief-set.md dispatch graph: Brief 6 marked NOT DISPATCHABLE
- brief-set.md §Brief 7 prerequisites: Briefs 1-5 + Phase 5 separately
- brief-set.md §Brief 7 scope: cites separately-scoped Phase 5 program
- brief-set.md §"Open questions for operator before dispatch" #1: RESOLVED
  per this codex BLOCKING; no FFI workaround acceptable

* WIP: Path B Brief 4 — M2 DB-10 data value semantics (data foo: T = v usable a

* docs(r3): finish typed emit error retraction
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant