Skip to content

v4 D1 — Diff/Path structural-delta vocabulary (operator ratification) - #3162

Merged
briansrls merged 25 commits into
mainfrom
session/valiant-boar-161
May 16, 2026
Merged

briansrls merged 25 commits into
mainfrom
session/valiant-boar-161

Conversation

@briansrls

@briansrls briansrls commented May 15, 2026 •

Copy link
Copy Markdown
Contributor

What this is

Encodes the side-session-ratified B-1 decision: the structural-delta
vocabulary over Node (the Diff type that affected_set consumes,
apply_diff produces, and incremental eval / structural caching key on).
This is a substrate addition to the immutable-header T-1 file, so the PR
is the operator-ratification vehicle (DECISIONS.md Part-5 flow).

Ratified (operator-decided in session)

  • Diff = a set of Edits; Edit replaces the subtree at a Path with
    a Node (term-rewriting t[s]p).
  • Path = List<EdgeSelector> (ByName/ByPosition, mirroring
    EdgeLabel). Flat & finite — NOT a new recursive type (A1: Node
    stays the sole recursion). This eliminates the "structural edit-script
    ADT" option outright.
  • Name is Path (the route), not Position (operator pick — a
    position is a coordinate; a path is how you get there). "position /
    occurrence" (JSON Pointer, RFC 6901) retained only as anchor citation.
  • Well-formed Diff = pairwise-independent Paths (term-rewriting
    "parallel positions") ⇒ apply_diff is deterministic-total or
    fail-closed. apply_diff consumer = CLI / test harness / app code.

Encoded in (4 files)

File Change
std/node.dag EdgeSelector/Path/Edit/Diff decls + D1 header block (DATA ONLY)
lens/application.dag subterm_at/apply_diff/predicate I/O contract in header (T-23 fill)
lens/affected_set.dag cross-ref: Diff is the consumed node.dag D1 type
DECISIONS.md Part-1 RATIFIED row D1

⚠️ One PROPOSED sub-point for your eye (confirm or redirect)

The session ratified "homed in std/node.dag". On encoding I hit a
forcing constraint and split it, which needs your confirmation:

  • Data types (EdgeSelector/Path/Edit/Diff) → std/node.dag ✅ (as
    ratified; B1/Hash precedent — a structural delta over Node is
    substrate-tier).
  • Operations (subterm_at/apply_diff → Result<Node,Diagnostic>,
    paths_independent/diff_well_formed) → lens/application.dag, not
    node.dag. Forced, not stylistic: std/diagnostic.dag already
    Consumes std/node.dag (Correction = Suggested(Node)), so a node.dag
    op returning Result<_,Diagnostic> is a substrate cycle. This is
    exactly node.dag's existing "the root declares the structural data +
    named invariant; CONSUMERS evaluate fail-closed" discipline (the
    node_well_formed precedent, node.dag ~L262).

Also corrected vs the initial briefing: the briefing said "owner = T-21"
and "Path is K-1-exempt like the diagnostics renderer." Both wrong —
single-authority puts the type in node.dag (not a lens), and Path
resolution needs only Symbol equality (K-1 grants that) so it is
K-1-clean, no exemption.

Status

Draft. Operator ratifies (confirm the data/op split) + merges per current
manual-merge policy. No code bodies added — node.dag gets inert data
decls; application.dag/affected_set.dag are scaffold (header contracts
only, bodies are T-23/T-21).

briansrls and others added 2 commits May 15, 2026 18:55
Side-session-ratified B-1. EdgeSelector/Path/Edit/Diff data types in
std/node.dag (DATA ONLY; A1-clean — Node stays the sole recursive type;
B1/Hash precedent for substrate-tier placement). Operations
(subterm_at/apply_diff -> Result<Node,Diagnostic>, paths_independent/
diff_well_formed) contracted into lens/application.dag header — forced
off node.dag by the diagnostic.dag->node.dag cycle (Correction=
Suggested(Node)); the node.dag "consumers fail-close" discipline.
affected_set.dag consumes the type. DECISIONS.md Part-1 row D1 carries
the data/op-split PROPOSED sub-point for operator confirmation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@briansrls briansrls changed the title v4 design v4 D1 — Diff/Path structural-delta vocabulary (operator ratification) May 15, 2026
@briansrls
briansrls marked this pull request as ready for review May 15, 2026 22:59

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

BLOCKING (2)

Root Cause

  • src/v4/std/node.dag D1 added structural-delta sum vocabulary without the required coproduct receipt → add the EdgeSelector classification with the attempted dissolution patterns or named scaffold trigger.
  • src/v4/std/node.dag The root-status constraint is driving the index carrier instead of the positional ontology → use a nonnegative index carrier such as Nat/Fin/PositionIndex or explicitly stage that gap with a dissolution trigger.

Non-blocking — Improvements (fix in-PR if easy, else defer to roadmap)

  • src/v4/DECISIONS.md The D1 row sits under RATIFIED while still asking for operator confirmation of the data/op split; either mark the split ratified or move that sub-point to a proposed/deferred T-23 note.

⚠️ Two substrate-shape issues should be fixed before this lands.

Comment thread src/v4/std/node.dag Outdated
// keeps this file's "Consumes: nothing" root status; an out-of-range
// or negative index simply fails Path resolution fail-closed in
// lens/application.dag — bounds are a resolution fact, not a type.
type EdgeSelector

This comment was marked as resolved.

Comment thread src/v4/std/node.dag Outdated
// lens/application.dag — bounds are a resolution fact, not a type.
type EdgeSelector
= ByName { name: Symbol }
| ByPosition { index: Int }

This comment was marked as resolved.

briansrls and others added 2 commits May 15, 2026 19:11
…ANGES)

Both findings valid; fixed structurally rather than patched.

Finding 1 (node.dag:~478 ByPosition{index:Int} admits negatives): drop
EdgeSelector/ByPosition entirely. Path = List<Symbol> — each step
descends the Named edge keyed by that opaque Symbol. No ordinal exists,
so the negative/out-of-range illegal state is structurally impossible
(dissolved, not deferred to path resolution). Positional-connective
children are reached by replacing the enclosing Named subtree (the safe
over-fire #3157 blesses); surgical positional addressing is a future
operator-ratified extension (consumes-nothing root has no Nat; recursive
Peano = A1 STOP).

Finding 2 (node.dag:~514 Diff=List<Edit> validity via external
predicate): drop the set / pairwise-independence / parallel-positions
framing and paths_independent/diff_well_formed. Diff = ORDERED List<Edit>
applied SEQUENTIALLY; any List<Edit> is a valid rewrite program (no
representable illegal state). A non-resolving Edit => fail-closed
Diagnostic at apply time (operational, not a type-level illegal state);
apply_diff is a fold, all-or-nothing.

Both refine the operator-ratified shape — flagged in DECISIONS.md D1
PROPOSED-for-operator-eye for confirm/redirect.

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

Copy link
Copy Markdown
Contributor Author

Addressed in 7c91f73 — both findings valid, fixed structurally (not patched):

Finding 1 (ByPosition{index:Int} admits negatives). Deleted EdgeSelector/ByPosition entirely. Path = List<Symbol> — each step descends the Named edge keyed by that opaque Symbol. There is no ordinal, so the negative/out-of-range illegal state is structurally impossible, not deferred to path resolution. Positional-connective children (Arrow/Cardinality/Instantiation) are reached by replacing the nearest enclosing Named subtree (the safe over-fire #3157 point 3 explicitly blesses); surgical positional addressing is a future operator-ratified extension — omitted because the consumes-nothing root has no ordinal primitive (no kernel Nat; a recursive Peano = A1 STOP). This aligns the Path layer with node.dag's own no-stored-positional-index design (lines ~221-230) instead of fighting it.

Finding 2 (Diff validity via external diff_well_formed). Dropped the set / pairwise-independence / "parallel positions" framing and paths_independent/diff_well_formed. Diff is now an ORDERED List<Edit> applied as SEQUENTIAL rewrites. Any List<Edit> is a valid rewrite program — no representable illegal state, nothing for an external predicate to recover. A non-resolving Edit ⇒ a fail-closed Diagnostic at apply time (legitimate operational behavior, not a type-level illegal state); apply_diff is a fold, all-or-nothing.

Both changes refine the operator-ratified shape and are flagged in DECISIONS.md D1 (PROPOSED-for-operator-eye) for confirm/redirect. The data/op split and cycle rationale are unchanged.

— sent from valiant-boar-161

…radiction (#3162 BLOCKING)

BLOCKING (codex via briansrls relay, vs pre-fix sha a06a066 — verified
against current HEAD):
- "D1 sum vocabulary without coproduct receipt": the EdgeSelector sum
  was already deleted in 7c91f73, but the DECISION not to have a
  positional selector is itself a Practice-4 dissolution requiring the
  formal 4-pattern ledger (algebra.dag precedent). Added the receipt to
  std/node.dag D1 (🟢 GREEN terminal: positional addressing subsumed by
  enclosing-Named-subtree replacement; not a deferred gap).
- "root-status driving the index carrier": resolved by the same
  dissolution — there is no index carrier; the receipt documents why
  none is needed (vs the reviewer's Nat/Fin suggestion) and why a
  future surgical form is an explicit operator-ratified extension.

Non-blocking: DECISIONS.md D1 row no longer carries a "confirm or
redirect" clause inside a RATIFIED row — refinements are stated as
encoded-via-PR-review (the normal channel), not an open fork.

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

Copy link
Copy Markdown
Contributor Author

BLOCKING addressed in 485f97e (verified against current HEAD, not stale-dismissed — findings were generated vs pre-fix sha a06a0666):

BLOCKING 1 — "D1 sum vocabulary without coproduct receipt." The EdgeSelector = ByName | ByPosition sum was already deleted in 7c91f738f (Path is now List<Symbol>, a record chain — no sum). But the decision not to have a positional selector is itself a Practice-4 dissolution, and the codebase requires the formal 4-pattern ledger for substrate-shape sum decisions (algebra.dag carries them for FreeMonoid/Ordering). Added that receipt to std/node.dag D1: 🟢 GREEN terminal — (1) fact-placement dissolves it (no D1 consumer needs positional-child addressing; everything factors through the Named step / enclosing-subtree replacement), (2) one-variant ⇒ payload ⇒ List<Symbol>, (3) N/A, (4) dimensional FAILS as a keep-reason. Not a deferred gap.

BLOCKING 2 — "root-status driving the index carrier." Resolved by the same dissolution: there is no index carrier. The receipt documents why none is needed (rather than the suggested Nat/Fin — positional addressing is structurally subsumed by enclosing-Named-subtree replacement, the safe over-fire #3157 point 3 ratifies) and why any future surgical positional form is an explicit operator-ratified substrate extension (the consumes-nothing root has no ordinal primitive; recursive Peano = A1 STOP), never a silent TODO.

Non-blocking — fixed in-PR: the DECISIONS.md D1 row no longer carries a "confirm or redirect" clause inside a RATIFIED row. The two refinements (data/op split; P2 shape change) are now stated as encoded via PR review (the normal channel), not an open fork.

— sent from valiant-boar-161

@briansrls

Copy link
Copy Markdown
Contributor Author

Verified against current HEAD (485f97e94) — already resolved, not stale-dismissed:

This inline comment targets src/v4/std/node.dag:476 on pre-fix sha a06a0666, where EdgeSelector = ByName | ByPosition was a live coproduct. Two commits since:

  • 7c91f738f deleted the EdgeSelector sum entirely — Path is now List<Symbol> (a record chain, no coproduct).
  • 485f97e94 added the Practice-4 dissolution receipt for that decision at node.dag:471-500 — explicit classification: 🟢 GREEN (DISSOLVED-AWAY, terminal) with the four-pattern ledger, exactly the modeling-discipline §4 artifact this finding asks for.

Concrete check: grep -rn 'EdgeSelector|ByPosition' src/v4/ returns a single hit — node.dag:474, which is inside the receipt comment, quoting the dissolved shape to document it. There is no type EdgeSelector declaration anywhere in src/v4/. The line the finding points at (476) is now line 3 of the receipt prose, not a sum declaration.

No further change needed for this item.

— sent from valiant-boar-161

@briansrls

Copy link
Copy Markdown
Contributor Author

Verified against current HEAD (485f97e94) — already resolved, not stale-dismissed:

This targets src/v4/std/node.dag:478 on pre-fix sha a06a0666, where ByPosition { index: Int } was a live selector variant (the negative-index-constructible concern — correct on that sha, and identical in substance to codex's earlier P2 Finding 1).

7c91f738f deleted that variant entirely. There is no Int ordinal selector anywhere in the substrate: Path = List<Symbol>, each step a Named-edge key resolved by opaque-Symbol equality. With no ordinal carrier, a negative/out-of-range selector is structurally unrepresentable — the illegal state is gone by construction, not deferred to a checker (the exact INVARIANTS P2 / M9 posture this finding asks for).

Concrete check — grep -rn 'index: *Int|ByPosition\{|type EdgeSelector' src/v4/ returns two hits, both comments:

  • node.dag:278 — the pre-existing EdgeLabel doc that argues against a stored Positional { index: Int } (the anti-pattern this file always rejected; unrelated to D1).
  • node.dag:474 — inside the D1 Practice-4 receipt, quoting the dissolved shape to document it.

No type EdgeSelector / ByPosition declaration exists. Line 478 on current HEAD is receipt prose, not a sum variant. The non-negativity is now enforced by the type not existing, which is strictly stronger than a Nat/Fin carrier. No further change needed.

— sent from valiant-boar-161

…3162 editorial)

The D1 header block cited "lines ~221-230" for the no-stored-index
discipline, but adding the D1 header block shifted line numbers — that
range is now `Connective`. Re-anchored by construct name + corrected
approx lines: `type EdgeLabel` ~284 and its "deliberately NO stored
index" rationale ~278. Editorial only; cursor APPROVE on this PR.

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

Copy link
Copy Markdown
Contributor Author

Thanks for the APPROVE. Editorial nit fixed in the follow-up commit: the D1 header block's lines ~221-230 cross-ref was stale (adding the D1 header block shifted line numbers — that range is now Connective, as you spotted). Re-anchored by construct name plus corrected approximate lines (type EdgeLabel ~284 and its "deliberately NO stored index" rationale ~278) so it's robust to future drift. No substantive change.

— sent from valiant-boar-161

briansrls and others added 4 commits May 15, 2026 19:34
Encodes the B-4 cross-cutting decision (operator-greenlit): affected_set
minimality requires 04_infer resolution to bind each use-site name-ref
to the EXACT declaration Node (not module/scope). The use->def graph is
derived by traversal over already-resolved name-references, NOT a 5th
InferredFacts field (IR-1-safe; same derive-don't-store discipline as
content_hash/D1). Coarse resolution = correct but maximally over-fires.

Reciprocal header contracts: 04_infer.dag B-4 block + affected_set.dag
Consumes note. DECISIONS.md Part-1 row B-4. Scaffold headers only; no
bodies. Continues the v4 design-survey on the session branch alongside
D1 (operator sequences/carves at manual merge).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
B-5 (affected_set R1 usefulness): effect is a per-Arrow-Node fact from
the signature (B3), never aggregated coarse — a granularity invariant
(coarse ⇒ R1 correct-but-useless). effect.dag B-5 block + affected_set
Consumes/Ex.R1 cross-ref + DECISIONS B-5 row.

Subsume #3153 (v4-affected-set-design, no worker — operator-directed):
its 4 worked-examples + adversarial R1/R2/R3 + dogfood-reality folded
into affected_set.dag as the T-21 design contract, reconciled to the
now-ENCODED reciprocal contracts — Ex.R1→B-5 (effect.dag), Ex.R2→B-4
(04_infer.dag), Ex.R3→B-3 (drafted #3157 point-3 correction). #3153
superseded; recommend close. DECISIONS #3153-subsumed row.

B-2 (PROOF-1 prover model lands): extdeps/languages/lean.dag (new) —
Lean first, termination theorem class; Coq deferred second-prover
probe. B2-OMNI requires the LanguageModel file PROOF-1 #3158 deferred.
STRUCTURE enumeration+count 63→64; DECISIONS L-4; TASKS PROOF-1 note.

Includes the already-committed origin/main merge (204b855: #3158
PROOF-1 + #3160 meta-cut; DECISIONS.md conflict resolved keeping
D1/B-4/PROOF-1).

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

BLOCKING (1)

Root Cause

  • src/v4/compiler/04_infer.dag B-4 is trying to avoid a fifth InferredFacts field but routes the dependency edge through the type fact instead of naming the resolved Atom/name-reference carrier → state that exact declaration identity survives on the resolved name-reference itself, or add an explicit non-InferredFacts carrier that affected_set consumes.

⚠️ One cross-stage fact-flow contract needs correction before this design contract lands.

Comment thread src/v4/compiler/04_infer.dag Outdated
// - A use-site is a name-reference `Atom`; its binding MUST resolve to
// the EXACT declaration `Node` it refers to — never merely that
// declaration's module/scope. Node-precise binding originates at
// compiler/03_resolve.dag and is preserved through `resolved_type`.

This comment was marked as resolved.

briansrls and others added 2 commits May 15, 2026 20:14
…3162 BLOCKING

Valid P2/Practice-3 finding (briansrls inline @ 04_infer.dag:54):
resolved_type is the node's TYPE; many declarations share a type, so it
is lossy for binding identity — the use→def fact had no named forward
carrier. Corrected: the carrier is the post-resolution opaque Symbol
(K-1) on the name-ref Atom, AUTHORED by 03_resolve.dag (binding =
Symbol equality, node.dag name_occurrences pattern). 04_infer is
preserve-only (no 5th InferredFacts field, IR-1-safe); affected_set
derives by Symbol-equality traversal. Fixed consistently across
04_infer.dag B-4 block, new 03_resolve.dag B-4 authority note,
affected_set.dag Consumes note, DECISIONS.md B-4 row.

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

Copy link
Copy Markdown
Contributor Author

Valid finding — fixed in the latest commit (not rebutted). You're right: resolved_type is the node's type (04_infer.dag:23); many declarations share a type, so it is lossy for binding identity — the use→def fact had no named forward carrier, a real Practice-3/P2 error in the B-4 wording.

Correction: the use→def carrier is the post-resolution opaque Symbol (K-1) on the name-reference Atom, not resolved_type. AUTHORITY is compiler/03_resolve.dag (it owns "identifier binding to declarations"): resolution canonicalizes a use-site Atom's Symbol to be identical to its binder declaration's Symbol, so binding = Symbol equality — the one K-1-granted operation, exactly node.dag's existing name_occurrences pattern, and the "resolved through the namespace" mechanism A1/K-1 already state. 04_infer is preserve-only (must not alter/drop the resolved Symbol; no 5th InferredFacts field — IR-1-safe). affected_set derives the graph by Symbol-equality traversal.

Fixed consistently in four places: 04_infer.dag B-4 block (rewritten), a new 03_resolve.dag B-4 authority note (binding is resolve's job, not infer's — which is exactly why resolved_type was the wrong carrier), affected_set.dag Consumes note, and the DECISIONS.md B-4 row. The fact now has a named, existing carrier with a single authority.

— sent from valiant-boar-161

@briansrls

Copy link
Copy Markdown
Contributor Author

Already addressed in e236d8883 — codex reviewed aa2bc7d9 (a merge commit); the fix commit is 2 commits after it (aa2bc7d9c → 1ac902324 WIP → e236d8883). Verified against current HEAD, not stale-dismissed.

codex's requested remedy: "state that exact declaration identity survives on the resolved name-reference itself, or add an explicit non-InferredFacts carrier." The fix takes the first option exactly. Current 04_infer.dag B-4 block:

NAMED CARRIER, not resolved_type: The use→def fact's forward carrier is the post-resolution opaque Symbol (K-1) on the name-reference Atom — NOT resolved_type. AUTHORITY is compiler/03_resolve.dag (binding = Symbol equality; node.dag name_occurrences). 04_infer is preserve-only (no 5th InferredFacts field).

So the declaration identity survives on the resolved name-reference Atom itself (its canonical Symbol, K-1), authored by 03_resolve, preserved (not re-carried) by infer — a named, existing, single-authority carrier, no fifth InferredFacts field, the dependency edge no longer routed through the type fact. Fixed consistently in 04_infer.dag (B-4 block), a new 03_resolve.dag B-4 authority note, affected_set.dag Consumes, and the DECISIONS.md B-4 row. This is the same root cause as the briansrls inline BLOCKING at 04_infer.dag:54, fixed in the same commit.

— sent from valiant-boar-161

@briansrls

Copy link
Copy Markdown
Contributor Author

Thanks. The exploratory point (Practice-4 receipts as a growing in-header prose anchor → maybe a sibling RECEIPTS.md / per-file .receipts.dag) is noted as a real watch-item, deliberately not actioned in this PR:

  • It is explicitly non-blocking and v4 D1 — Diff/Path structural-delta vocabulary (operator ratification) #3162 is merge-ready — a receipts-relocation refactor here would be scope-creep and reset the approval cycle for zero correctness change.
  • More substantively: where Practice-4 receipts live (in-header vs a new sibling file) is a substrate-organization decision under STRUCTURE.md's closed-file-tree invariant — adding RECEIPTS.md is an operator-ratified file addition, not a worker call. Pre-empting it unilaterally would itself violate invariant Add SVG viz, test helpers, and makegen scaffold #1.
  • The tradeoff is real both ways: in-header keeps the dissolution argument adjacent to the type it justifies (the reviewer-validates-against-anchor discipline); a sibling file keeps headers contract-focused but splits the receipt from its subject. That's a genuine design fork for the operator, captured for the design ledger — not silently dropped.

Recorded as a design-consideration to route to the operator; no code change here.

— sent from valiant-boar-161

briansrls and others added 3 commits May 15, 2026 20:46
C5-2 (emit-locality): emit is structurally local — a D1 apply_diff at
Path p re-emits ONLY p's subtree. Per operator code-as-data steer:
locality is Node-relative, NOT file-relative; a file is a convenience
projection, the substrate anchors no semantic on the file concept;
non-local emit = declared normalization at the enclosing NODE scope,
never "file scope". The C5↔D1 hinge (AGENT-1 faithful re-emit).
05_emit.dag header + Owns + DECISIONS C5-2 row.

T-9 A+B: A — Find decidable by construction (closed declared-inhabitance
candidate set, not a synthesized search; structural descent ⇒ the
inferencer terminates; empty = decidable fail-closed Diagnostic).
B — single-file discipline is the 03_resolve scope boundary (env/scope/
lookup/binding belongs to 03_resolve per B-4; infer owns only Find +
cardinality + diagnostic precision). 04_infer.dag header + DECISIONS
T-9 row.

Receipts: in-header (operator decision; status quo, no change).

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

Copy link
Copy Markdown
Contributor Author

Valid — fixed (not rebutted). docs/modeling-discipline.md:112 does require five dissolution patterns (Pattern 5 = Parameterized family, explicitly the one Patterns 1–4 won't catch). The D1 receipt recorded only four; added Pattern 5:

5. Parameterized family — FAILS: ByName/ByPosition are not one mechanical F<X> over a separately-declared set (different payload types Symbol/Int + different addressing semantics; they mirror node.dag's genuine 2-variant EdgeLabel discriminant, not an enumerated copy of a declared selector-kind set — contrast the Pattern-5 Homomorphism-per-algebra example). No source set X to project over ⇒ Practice-7 projection N/A. Post-(1), one constructor remains — a one-element family is not a family.

Classification stays 🟢 GREEN (dissolved by Pattern 1) but the ledger is now complete against the 5-pattern bar. This also aligns the D1 receipt with the #3160 operator-ratified node.dag receipts, which already use the 5-pattern form (node.dag:241 etc.) — the in-file precedent I should have matched.

Note (out of scope for this PR, flagging not fixing): std/algebra.dag's FreeMonoid/Ordering receipts appear to be 4-pattern (the older style I mistakenly copied) — a pre-existing inconsistency vs the rubric in already-merged code; surfacing for a separate pass rather than silently absorbing it here.

— sent from valiant-boar-161

@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: 5f509179 · Trigger: schedule
  • Thinking: 340s wall

✅ No blocking concerns; the PR resolves the prior substrate issues and keeps the new D1/B-4 contracts aligned with the Node-centered v4 model.

…-provable F

C5-1: the bidirectional_roundtrip TestClaim asserts ingest∘emit=id_Node
via B1 content_hash (meaning round-trips), NOT text-byte identity.
Text-level fidelity recorded as a DEFERRED orthogonal future layer (a
trivia sidecar outside Node/content_hash, partial; the C5-fidelity
Declared-normalized dispositions are its forward hook — node-level
adoption preserves it zero-rework). Non-orthogonal route (lexical in
the Node) explicitly rejected.

C5-3: F = the spec-provable meaning core; spec silence ⇒ out of F
(Declared-normalized or Fail-closed). Conservative/fail-safe — the
spec decides, modeler has no discretion; per-language non-F shrinkage
declared up front, not discovered at test time.

Encoded: lens/testgen.dag C5-1/C5-3 header block + DECISIONS C5-1/C5-3
rows.

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

Both valid; the D1↔AGENT-1 reconciliation.

:52 — apply_diff:(Node,Diff)->Node is total on EXTERNAL (agent-supplied,
possibly invalid/stale) input = fail-open, INVARIANTS P3. D1 (#3162)
already ratified the correct shape: apply_diff:(Node,Diff)->
Result<Node,Diagnostic>, fail-closed all-or-nothing. AGENT-1 now USES
the D1 op (not a restated total one). application.dag WRITE + DECISIONS
AGENT-1 row.

:59 — AGENT-1 coined `Witness<ReExecFrontier>` for BACK = an ungrounded
noun while claiming "no new authority" (P1/P2). AGENT-1 is a CLIENT:
it now defers to affected_set/T-21's OWN declared read shape and coins
no return noun. Faithful re-emit tied to the ratified C5-1 (node-level
hash-checked) + C5-2 (emit-locality) + C4.

Pre-existing QRY-1 block (application.dag ~L31) still cites
Witness<ReExecFrontier> as affected_set's archetype — that, and
whether affected_set.dag's declared return is Witness<ReExecFrontier>
vs Set<NodeRef>/receipts, is an affected_set/T-21 concern (surfaced,
not silently changed here — out of #3155 scope).

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: 3763e4d5 · Trigger: schedule
  • Thinking: 249s wall

Non-blocking — Strengths

  • src/v4/std/node.dag The D1 Path/Edit/Diff shape is single-authority substrate data and keeps fail-closed operations out of node.dag to avoid the diagnostic cycle.
  • src/v4/extdeps/languages/lean.dag The Lean scaffold is documented, bounded to the PROOF-1 termination target first, and defers Coq as a named future probe.

✅ No blocking concerns; the PR resolves the prior substrate issues and keeps the new v4 D1, B-4, B-5, C5, and PROOF-1 contracts aligned with the thesis.

@briansrls

Copy link
Copy Markdown
Contributor Author

Valid (NON-BLOCKING) — fixed for self-consistency. The B-2 work added extdeps/languages/lean.dag + the L-4 row, but I left the PROOF-1 row ending "NO new file (closed-tree invariant)", which a worker reading the table literally sees as contradicting L-4. Reconciled into one story:

PROOF-1's framing (#3158) added NO new file — it was framing-only and explicitly DEFERRED the prover model ("realized when a lean/coq model lands"); that model subsequently lands as extdeps/languages/lean.dag per B-2/L-4 (operator-ratified closed-tree extension — see the L-4 row). No contradiction: framing = no file; the deferred model's later arrival is the L-4 extension.

The PROOF-1 row now cross-references L-4 and states the no-contradiction explicitly, so the decision table has a single coherent narrative. (Re: the exploratory note that the bundle is wider than the "D1" title — correct; #3162 became the v4 design-survey branch carrying D1 + B-4/B-5 + C5-1/2/3 + T-9 + B-2/L-4 as the operator directed continued encoding here; the commits + DECISIONS rows tell that single-branch story.)

— sent from valiant-boar-161

briansrls and others added 4 commits May 16, 2026 03:10
…ursor #3162 APPROVE_WITH_COMMENTS)

Valid NON-BLOCKING finding: B-2 added lean.dag + the L-4 row but the
PROOF-1 row still ended "**NO new file** (closed-tree invariant)",
contradicting L-4 (which lands extdeps/languages/lean.dag). Reconciled:
PROOF-1's framing (#3158) added no file (framing-only, deferred the
model "lands later"); that deferred model subsequently lands as
lean.dag per B-2/L-4. One coherent story; PROOF-1 row now cross-refs
L-4 and states "No contradiction" explicitly.

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

* v4 AGENT-1: place the non-text agent-surface contract (no new file)

Operator-ratified 2026-05-15: include & design early, explicitly NOT the
north star; an important/exclusive feature but a natural consequence of
already-ratified pieces, not a new subsystem.

A non-text client (LLM/agent) interacts with the program as data, never
files: READ = apply_lens at SectionRef + affected_set(dag,diff) (the
affected lens replaces file-reading exploration); WRITE = a structural
Node Diff = an ingest (B2-OMNI), content-addressed (B1), not a text
patch; BACK = Witness<ReExecFrontier> + faithful re-emit (C5/C4); GATE =
apply_lens(Enforce) fail-closed (agent earns no special trust).

Homed in lens/application.dag (T-23) as a conspicuous AGENT-SURFACE
block — a CLIENT/composition of application.dag + affected_set + B2-OMNI
+ C5/C4, no new authority/noun/query subsystem (QRY-1 precedent). No new
file (closed-tree invariant preserved). Cross-ref back-pointer in
00_compile.dag B2-OMNI; DECISIONS.md AGENT-1 row; TASKS.md T-23 note.
affected_set.dag back-ref deferred to avoid conflict with PR #3153.

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

* v4 AGENT-1 fix: write path enters at `core` (apply_diff), NOT ingest

Self-correction. B2-OMNI `ingest:(Source,LanguageModel)->Node` is text-in-
a-language → Node. An agent's structural Node Diff is ALREADY Node — it
needs no parse/LanguageModel, so it is NOT a Source and NOT an ingest.
Correct model: `apply_diff:(Node,Diff)->Node` entering at `core` —
`emit ∘ core ∘ apply_diff`, a sibling entry point to ingest. Forcing it
through ingest would need a contrived identity "Node-literal language"
(the decorative bridge the closed system forbids). Fixed in
application.dag (WRITE + BOUNDARY), 00_compile.dag back-ref,
DECISIONS.md AGENT-1 row, TASKS.md T-23 note.

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

* v4 AGENT-1: fix 2 BLOCKINGs — fail-closed apply_diff + defer to affected_set (briansrls #3155)

Both valid; the D1↔AGENT-1 reconciliation.

:52 — apply_diff:(Node,Diff)->Node is total on EXTERNAL (agent-supplied,
possibly invalid/stale) input = fail-open, INVARIANTS P3. D1 (#3162)
already ratified the correct shape: apply_diff:(Node,Diff)->
Result<Node,Diagnostic>, fail-closed all-or-nothing. AGENT-1 now USES
the D1 op (not a restated total one). application.dag WRITE + DECISIONS
AGENT-1 row.

:59 — AGENT-1 coined `Witness<ReExecFrontier>` for BACK = an ungrounded
noun while claiming "no new authority" (P1/P2). AGENT-1 is a CLIENT:
it now defers to affected_set/T-21's OWN declared read shape and coins
no return noun. Faithful re-emit tied to the ratified C5-1 (node-level
hash-checked) + C5-2 (emit-locality) + C4.

Pre-existing QRY-1 block (application.dag ~L31) still cites
Witness<ReExecFrontier> as affected_set's archetype — that, and
whether affected_set.dag's declared return is Witness<ReExecFrontier>
vs Set<NodeRef>/receipts, is an affected_set/T-21 concern (surfaced,
not silently changed here — out of #3155 scope).

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

* v4 AGENT-1: fix the missed 00_compile.dag apply_diff residual (openai-pro #3155 REQUEST_CHANGES)

openai-pro correctly caught that the prior BLOCKING fix
(application.dag + DECISIONS.md → Result<Node,Diagnostic>) MISSED the
00_compile.dag:18 back-ref, which still showed the total
apply_diff:(Node,Diff)->Node. Fixed: it now mirrors ingest's own
->Result<Node,Diagnostic> (sibling at `core`), fail-closed on
external/stale agent Diffs (INVARIANTS P3). All three #3155 surfaces
(application.dag, DECISIONS AGENT-1 row, 00_compile.dag) now state the
D1 fail-closed signature consistently.

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

* v4 AGENT-1: fix the last residual — TASKS.md T-23 note (codex #3155 REQUEST_CHANGES)

codex correctly caught the 4th surface I'd missed: #3155 changed
DECISIONS/application.dag/00_compile.dag/TASKS.md; prior fixes covered
the first three but TASKS.md:74-80 still carried the total
apply_diff:(Node,Diff)->Node + the removed Witness<ReExecFrontier>
AGENT-1 noun = parallel authority / internal inconsistency. Now the
T-23 note matches the other three: D1 apply_diff:(Node,Diff)->
Result<Node,Diagnostic> (fail-closed, P3) + defers to affected_set's
declared shape (no coined noun). All four AGENT-1 surfaces consistent.

(TASKS.md:614 + DECISIONS QRY-1 cite Witness<ReExecFrontier> as
affected_set's OWN archetype — pre-existing, the affected_set/T-21
declared-shape concern already surfaced separately; out of #3155 scope.)

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
# Conflicts:
#	src/v4/DECISIONS.md
#	src/v4/lens/application.dag
#	src/v4/std/node.dag
@briansrls

Copy link
Copy Markdown
Contributor Author

Review metadata

  • Provider / model: openai-pro / gpt-5-5-pro
  • Commit: 8404cddf · Trigger: manual
  • Comparison: main @ eabfa71b ... session/valiant-boar-161 @ 8404cddf
  • Conversation: View conversation

1. Story of the diff

This PR is primarily a v4 design-ratification pass that turns “structural delta over Node” into a named substrate vocabulary and then threads the consequences through the neighboring contracts. The load-bearing move is in src/v4/std/node.dag: Path, Edit, and Diff are declared as data over Node, with Path restricted to List<Symbol>, Edit replacing a subtree with a Node, and Diff as an ordered sequential List<Edit> rather than a set plus a validity predicate (src/v4/std/node.dag:740, src/v4/std/node.dag:749, src/v4/std/node.dag:767). The operation side is intentionally kept out of std/node.dag: subterm_at and apply_diff are specified in lens/application.dag because they return Diagnostic, and putting them in node.dag would create a node ↔ diagnostic dependency cycle (src/v4/lens/application.dag:52–65).

The rest of the diff ratifies the surrounding semantics that make that vocabulary usable: affected-set reads Diff but does not own it (src/v4/lens/affected_set.dag:14–19), resolve/infer establish the node-precise Symbol carrier for use→def identity (src/v4/compiler/03_resolve.dag:11–25, src/v4/compiler/04_infer.dag:49–80), effect granularity is pinned per Arrow/signature rather than ambiently (src/v4/lens/effect.dag:14–31), and emit/testgen get the C5 locality and node-level roundtrip contracts that D1 needs (src/v4/compiler/05_emit.dag:24–48, src/v4/lens/testgen.dag:54–80). Separately, the PR reconciles PROOF-1 by adding the first prover language model, extdeps/languages/lean.dag, as a scoped Lean 4 scaffold for termination proofs, and updates DECISIONS.md, STRUCTURE.md, and TASKS.md to make that extension explicit (src/v4/extdeps/languages/lean.dag:3–27, src/v4/TASKS.md:94–100).

2. Invariant categories

  1. LAYER MODEL — Compliant. The diff does touch substrate: D1 data lands in std/node.dag, while diagnostic-returning operations are deliberately moved to lens/application.dag to avoid a substrate cycle (src/v4/std/node.dag:142–150, src/v4/lens/application.dag:52–60). That split preserves the substrate/consumer boundary instead of making node.dag depend back on diagnostics.
  2. INVARIANTS.md + modeling-discipline.md — Compliant. The illegal-state surface from a positional selector is dissolved rather than retained: Path is only List<Symbol> (src/v4/std/node.dag:107–111, src/v4/std/node.dag:740–742), ordinal addressing is explicitly rejected because Int admits negative/out-of-range states (src/v4/std/node.dag:112–128), and the prior selector coproduct gets a five-pattern Practice-4 receipt (src/v4/std/node.dag:680–728). Fail-closed is also preserved: unresolved paths become diagnostics in subterm_at/apply_diff, never guesses (src/v4/lens/application.dag:16–24), and Diff is sequential data rather than a predicate-repaired set (src/v4/std/node.dag:129–141, src/v4/std/node.dag:755–769).
  3. CODING.md — Compliant. There is no new Rust implementation surface; the .dag operations are specified as named functions over explicit inputs, not methods or hidden-state helpers: subterm_at(root: Node, p: Path) -> Result<Node, Diagnostic> and apply_diff(root: Node, d: Diff) -> Result<Node, Diagnostic> (src/v4/lens/application.dag:16–24). The new Lean target is also data/spec scaffold, not procedural emitter code (src/v4/extdeps/languages/lean.dag:29–44).
  4. TESTING.md — N/A. This diff does not add executable Rust behavior or a runnable .dag implementation; it ratifies scaffold contracts. The future runnable surfaces are explicitly named as fill work rather than silently claimed as implemented: Lean is “Status: scaffold — fill per TASKS.md PROOF-1 (T-15)” (src/v4/extdeps/languages/lean.dag:52–57), and the D1 operations are “part of this file’s T-23 fill” (src/v4/lens/application.dag:61–65).
  5. LOCKED DESIGN DECISIONS — Compliant. The diff does alter/clarify locked design posture, but does so explicitly in DECISIONS.md: PROOF-1’s prior “no new file” framing is reconciled with the later Lean model landing via L-4 (src/v4/DECISIONS.md:41, src/v4/DECISIONS.md:50), and TASKS is updated to say the prover model now lands as extdeps/languages/lean.dag while PROOF-1 completes when the lens framework composes with it (src/v4/TASKS.md:94–100). I do not see a silent divergence from a locked decision.
  6. TRACKED vs UNTRACKED DEBT — Compliant. The new scaffolds are bounded and named. Lean is scoped to Lean 4, termination first, spec-not-Mathlib, with Coq explicitly deferred as a future operator-ratified second-prover probe (src/v4/extdeps/languages/lean.dag:8–13, src/v4/extdeps/languages/lean.dag:20–27, src/v4/extdeps/languages/lean.dag:52–57). Text-level fidelity is marked as an orthogonal future sidecar outside Node and content_hash, not a partial D1/C5 implementation (src/v4/lens/testgen.dag:71–79). I did not find a new TODO/bridge without documentation, bounds, and a dissolution or ratification path.

2.5. Top-down PM intent review

Compliant. From the PM/executive level, this PR preserves the v4 intent rather than diluting it: D1 becomes substrate data over Node, not a lens-private side type (src/v4/std/node.dag:151–155); operations stay in a consumer layer to avoid dependency cycles (src/v4/lens/application.dag:52–60); affected-set minimality is grounded in forward-carried Symbol identity rather than a lossy inferred type (src/v4/compiler/04_infer.dag:52–73); and Lean is added as a declarative language model, not as hand-written prover logic (src/v4/extdeps/languages/lean.dag:29–38). I do not see a must-have target becoming optional, a dissolution goal turning into permanent scaffolding, or hand-written implementation replacing the bootstrap/data-authored direction.

3. Verdict

APPROVE. The PR cleanly ratifies the D1 vocabulary, removes the two obvious illegal-state risks from the earlier shape, and keeps authority split across substrate data, application operations, resolve/infer carriers, and affected-set/effect consumers. No diff-cited blocking or non-blocking findings from me.

Exploratory observations

One seam to watch when T-21/T-23 becomes executable: affected_set says it consumes Diff but “never applies it” (src/v4/lens/affected_set.dag:14–19), while apply_diff is where path failure becomes diagnostic (src/v4/lens/application.dag:19–24). The current design is coherent if callers sequence “apply or validate first, then compute frontier”; when implementation lands, that precondition should be made explicit in the API shape or enforced by the runner so invalid diffs cannot produce authoritative frontier witnesses.

@briansrls
briansrls merged commit a4d6a9f into main May 16, 2026
7 checks passed

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Review metadata

  • Provider / model: codex / unknown
  • Commit: 06ab1967 · Trigger: schedule
  • Thinking: 251s wall

✅ No blocking concerns in the current diff.

briansrls added a commit that referenced this pull request May 16, 2026
…List<BootstrapStep>

Addresses BLOCKING review (bootstrap.dag:190): steps: List<BootstrapStep>
admitted reordered/duplicated/missing/extra chains — the
seed-once→stage0→stage1→stage2→fixed-point invariant was prose-only
(INVARIANTS P2). The chain is fixed by STRUCTURE.md (zero degrees of
freedom), so BootstrapPlan is now a FIXED RECORD with four named
positional slots whose distinct slot TYPES (CompileStep / FixedPointStep)
pin compile-vs-fixedpoint per position. Dissolves the exact node.dag
Diff #3162 list-anti-pattern. BootstrapStep coproduct removed (kind is
now the slot type, not a variant); Stage coproduct + its Practice-4
ledger retained unchanged (still consumed by the step records — no
finding-#1 churn). Within-step Stage wiring is a documented bounded
residual (yaml lexeme class; mis-wire = fail-closed interpret-time
Diagnostic, the ratified Diff stance — not a type-level illegal state).
Structural v2-compile gate re-verified (64 modules, 0 diagnostics).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request May 17, 2026
…de.dag Diff #3162 stance)

Addresses briansrls BLOCKING (ci.dag:275): jobs/gates lists + raw
Symbol edges leave missing targets / duplicate ids / needs-cycles
constructible; P2/P4 need a structural OR fail-closed boundary before
consumers land.

Resolved by applying the canonical node.dag Diff #3162 ratification
(not a coin-flip — that precedent settles the shape): ANY jobs/gates
lists are valid CiPipeline DATA; missing-target/dup-id/cycle are NOT
type-level illegal states and there is deliberately NO
ci_pipeline_well_formed eager predicate (exactly the #3162
diff_well_formed anti-pattern). The fail-closed WELL-FORMEDNESS
boundary is the deferred select_jobs consume fold (apply_diff-analogous
all-or-nothing): unresolved/duplicate/cyclic => one fail-closed
Diagnostic (Outcome<T>), decidable via visited-set traversal (P4).
NAMED + OWNED now (select_jobs / lens/affected_set.dag T-21, TRACKED
SCAFFOLD (2)); only its body deferred per scaffold discipline. Doc
tightened in CiPipeline + TS(2). Comment-only; structural v2-compile
gate GREEN (64 modules, 0 diagnostics).

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

still-hawk-102 (relayed via Lane B) rejected reaffirming #3162 for
CiPipeline: #3162's precondition (no intrinsic well-formedness) is FALSE
here — a job/gate DAG has intrinsic, statically-decidable
well-formedness (unique ids / acyclic / resolving refs), malformed
independent of any consumer; deferring to select_jobs (a consumer) is
ruled out by the operator's "before consumers land". Patterns don't
auto-extend without the per-instance precondition.

Implemented the eager boundary NOW: ci_pipeline_well_formed :
CiPipeline -> Outcome<CiPipeline>, covering (1) unique job ids
(node.dag all_names_distinct CHECK-enforced precedent), (2) reference
resolution (every needs/gate.job resolves to a declared id), (3)
acyclicity via Kahn sink-elimination bounded by count(jobs) passes
expressed as a fold over the finite jobs list (A2 IMPLICIT termination,
INVARIANTS P4) — never an unbounded walk. Any violation = one
fail-closed Diagnostic (AmbiguousIntent, no repair-guess). Structural
Map-for-ids was INFEASIBLE: v4 Map<K,V> is lookup-only (no key
enumeration) so a Map jobs field can't be traversed for the required
acyclicity/ref checks; jobs/gates stay List (fold-traversable) per the
adjudication's "pick by feasibility" + ACCEPTABLE eager option. NOT a
#3162 exception (#3162 never governed this carrier). WELL-FORMEDNESS
header + TRACKED SCAFFOLD (2) rewritten (drop #3162-stance + the
deferral). Structural v2-compile gate GREEN (64 modules, 0 diagnostics).

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

Per still-hawk-102 STRICT DE-PROSE RE-DO (supersedes prior nominal
de-prose; prior attestation not accepted). A de-prosed .dag carries
ONLY: file-path line; terse Scope/Owns/Consumes/Status header; optional
per-carrier Anchor URL; optional one-line per-TYPE concept tag if
non-obvious. Everything else removed. Comment-only — all code, types,
fns, data verbatim-unchanged; structural v2-compile gate GREEN (64
modules, 0 diagnostics).

Comment-% (was → now): bootstrap.dag ~83% → 19.2% (5/26);
ci.dag ~58% → 3.2% (5/156). Both < 20% hard target.

PROCESS RECEIPT / removed-narrative provenance (kept here in the commit
message per directive, NOT in the file):
- ci.dag D5 HEADER RECONCILE (2026-05-17, #3213, D5/#3216, #3190
  precedent): operator-tier BLOCKING review actions (briansrls inline
  C4-fabrication + single-authority-seam; openai-pro confirming) moved
  the body past the frozen Owns/C4 header; it was reconciled IN-PR to
  the single-authority project_github_actions->Workflow seam with C4
  gated on the missing v4 Workflow substrate (interim hand-authored
  ci.yml bridge). C4 operator-ratified intent preserved; only mechanism
  corrected. This narrative now lives only in git history + prior PR
  comments, not the file.
- ci_pipeline_well_formed is the eager fail-closed well-formedness
  boundary (still-hawk-102 adjudication 2026-05-17): #3162 does not
  govern CiPipeline (intrinsic statically-decidable well-formedness);
  structural Map-for-ids INFEASIBLE (v4 Map<K,V> is lookup-only, no key
  enumeration) so jobs/gates stay List + eager predicate checks unique
  ids (node.dag all_names_distinct precedent) + ref-resolution +
  acyclicity (Kahn elimination bounded by count(jobs), A2-IMPLICIT,
  P4-decidable). Architectural rationale belongs in DECISIONS.md (owned
  by operator/#3226), not this file.
- No D2-alias prose present (not D2-affected, not pipeline-stage); no
  gated reconciliations. Branch 0 commits behind origin/main.

HELD for operator audit; not merging (operator squash-merge only).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request May 18, 2026
…apPlan data + CiPipeline C4 seam) (#3213)

* v4 T-20+T-24: model workflow/bootstrap.dag + workflow/ci.dag — BootstrapPlan data (v2-interp) + CiPipeline C4 ci.yml projection seam

T-20 workflow/bootstrap.dag: Stage / BootstrapStep / BootstrapPlan as
inert data; canonical seed→self0→self1→fixpt plan. Interpretation
(process/fs spawn) + executable BitIdentical TestClaim deferred (TRACKED
SCAFFOLD; owners T-22/T-4.5 and T-15).

T-24 workflow/ci.dag: CiJob / CiGate / CiPipeline data; Symbol-edge job
DAG; canonical structural v2-compile gate instance (the existing day-1
gate). ci.yml C4 projection, affected-set selection (IB-2), and
test/eval lane deferred (TRACKED SCAFFOLD; owners T-4.6/T-10, T-21, T-22).

Structural v2-compile gate verified: v2-compiler indexes 64 modules,
0 diagnostics. Status-line bump only; Owns/Consumes/Scope/Anchor headers
unchanged.

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

* v4 T-20: add Practice-4 🟢/🟡/🔴 + five-pattern ledger to Stage + BootstrapStep coproducts

Addresses BLOCKING review (bootstrap.dag:160): every substrate coproduct
must carry the full Practice-4 classification + five-pattern dissolution
ledger under INVARIANTS P1 / modeling-discipline.md §4. Both Stage and
BootstrapStep classified 🟢 GREEN (terminal) with the five patterns
(fact-placement / variant-is-data / algebraic / dimensional /
parameterized-family) attempted inline, mirroring the witness.dag
exemplar. The inadequate one-line note replaced with a forward pointer.
Comment-only; structural v2-compile gate re-verified (64 modules, 0
diagnostics).

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

* v4 T-20: make the bootstrap chain structural — fixed record replaces List<BootstrapStep>

Addresses BLOCKING review (bootstrap.dag:190): steps: List<BootstrapStep>
admitted reordered/duplicated/missing/extra chains — the
seed-once→stage0→stage1→stage2→fixed-point invariant was prose-only
(INVARIANTS P2). The chain is fixed by STRUCTURE.md (zero degrees of
freedom), so BootstrapPlan is now a FIXED RECORD with four named
positional slots whose distinct slot TYPES (CompileStep / FixedPointStep)
pin compile-vs-fixedpoint per position. Dissolves the exact node.dag
Diff #3162 list-anti-pattern. BootstrapStep coproduct removed (kind is
now the slot type, not a variant); Stage coproduct + its Practice-4
ledger retained unchanged (still consumed by the step records — no
finding-#1 churn). Within-step Stage wiring is a documented bounded
residual (yaml lexeme class; mis-wire = fail-closed interpret-time
Diagnostic, the ratified Diff stance — not a type-level illegal state).
Structural v2-compile gate re-verified (64 modules, 0 diagnostics).

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

* v4 T-24: make the C4 ci.yml claim honest — no fabrication of GHA transport facts

Addresses BLOCKING review (ci.dag:146): CiPipeline {jobs,gates} cannot
faithfully back a .github/workflows/ci.yml C4 projection — a faithful
GHA workflow needs on/runs-on/steps/concurrency/permissions, which the
gunbc job/gate DAG deliberately omits, so any CiPipeline->ci.yml emit
would fabricate them (INVARIANTS P1/P2).

Fix is honesty, not fabrication and not a substrate add: project_ci_yml
re-typed to also consume a GHA workflow-schema model (gunbc data fills
the schema, never invents it); that schema is named MISSING SUBSTRATE
(no v4 counterpart to v3 extdeps/github/actions.dag — a new file =
operator-tier, surfaced not added). Committed ci.yml reframed as the
explicit interim hand-authored BRIDGE (the affected_set.dag
detect-affected-components.sh precedent); C4 checked-projection is an
explicit future state gated on the named substrate. The immutable
header's Owns/C4-over-CiPipeline over-claim is flagged on the PR for
conscious operator confirmation (frozen-header lines NOT worker-edited).
Structural v2-compile gate re-verified (64 modules, 0 diagnostics).

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

* v4 T-20: comment hygiene — drop stale BootstrapStep refs from current-tense prose

Addresses cursor/composer-2 APPROVE_WITH_COMMENTS: two comments still
named BootstrapStep in the present tense after it was dissolved into
CompileStep/FixedPointStep slots. Fixed the "DATA, not a runner"
paragraph (now: fixed BootstrapPlan record of named slots) and the
Stage ledger pattern-1 (now: every chain step CompileStep/FixedPointStep).
The two remaining BootstrapStep mentions are intentional
removal-provenance, kept. Comment-only; structural v2-compile gate
re-verified (64 modules, 0 diagnostics).

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

* v4 T-24: defer C4 seam to the ratified single-authority Workflow path (not a worker-minted shape)

Addresses BLOCKING (ci.dag:120): the db725fc C4 fix minted a parallel
project_ci_yml(CiPipeline, GhaWorkflowSchema) -> YamlValue seam,
diverging from the ratified locked T-Workflow-As-Data path
project_github_actions(CIWorkflowDag, WorkflowRuntime) -> Workflow
(extdeps.github.actions { Workflow } single authority pinned on
gunbc.ci CIWorkflowDag; WorkflowRuntime = YamlStatic | BinaryShim;
dsl/gunbc/ci_emission.dag) — parallel authority, INVARIANTS P2 (the
SELF_HOSTING authority-audit precedent).

Fix: the deferred seam now defers to the ratified single-authority
Workflow carrier + project_github_actions/WorkflowRuntime seam; ci.yml
is the Workflow carrier serialized under YamlStatic (YAML downstream of
Workflow), never a parallel CiPipeline -> YamlValue projection. The
invented GhaWorkflowSchema/project_ci_yml shape is retracted (kept as
provenance, not silently dropped). Missing substrate re-stated as the
v4 counterpart of the ratified extdeps.github.actions Workflow carrier
+ ci_emission.dag seam (operator-tier new file, surfaced not added, not
worker-substituted). No-fabrication / interim-bridge / header-tension-
surfaced stance preserved. Structural v2-compile gate re-verified (64
modules, 0 diagnostics).

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

* WIP: IB-3 T-20+T-24 workflow/bootstrap.dag + workflow/ci.dag — BootstrapPlan

* v4 T-20: make bootstrap chain edge identity structural now (singleton steps; zero inhabitants of invalid plans)

Addresses openai-pro REQUEST_CHANGES (843a37f, the binding gate) +
operator P2 finding: the free-field CompileStep/FixedPointStep records
still admitted the exact mis-wiring (seed slot typed-valid with
produces:Stage2) the comments claimed eliminated — the source/target
edge is the fixed chain's structural identity, not user config, so it
must be structural NOW, not an interpret-time check.

Each of the four positions is now its own payload-less SINGLETON
edge-identity type (SeedToStage0 / Stage0ToStage1 / Stage1ToStage2 /
FixptStage1Stage2; verified v2 parses `type X = X`). BootstrapPlan is
the fixed record of those slots → exactly ONE inhabitant; reorder /
duplicate / missing / extra / mis-wire all unconstructible. The Stage
coproduct (+ its five-pattern ledger) and BootstrapStep are both
removed (stage/edge identity now in the singleton names); no coproduct
remains so no Practice-4 ledger applies — this moots the earlier
"Stage/BootstrapStep need ledgers" finding by dissolution. The earlier
"bounded residual / future-grammar" deferral is retracted as
unnecessary (provenance kept, not silently dropped). Structural
v2-compile gate re-verified (64 modules, 0 diagnostics).

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

* v4 T-20: fix singleton step types — empty-record form (constructible); restores green gate

bfc8886 used `type X = X` which v2 parses as a type but provides NO
usable value constructor (`undefined variable` at the data
construction) — that commit broke the structural v2-compile gate (4
errors). Root cause: the earlier probe only DECLARED the singleton,
never CONSTRUCTED it. Fixed: the four chain-position singletons are
empty records `type X {}` constructed as `X {}` (verified: v2 parses
AND constructs this form, 0 diagnostics). Design intent unchanged —
BootstrapPlan still has exactly one inhabitant; mis-wiring
unconstructible (openai-pro REQUEST_CHANGES + operator P2 resolved
structurally). Prose updated (empty-record singleton, not `type X = X`).
Structural v2-compile gate re-verified GREEN (64 modules, 1 file
emitted, 0 diagnostics, no errors).

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

* v4 T-24: D5 in-PR frozen-header reconcile for ci.dag Owns/C4 (cite operator-tier review actions)

Per DECISIONS.md D5 / PR #3216 standing rule (merry-ibex-337 -> Lane B,
#3190 precedent): operator-tier action moving the body past the frozen
header/I/O ⇒ reconcile the header in the SAME PR + HEADER RECONCILE
block citing it; verbatim-while-divergent body = forbidden unsanctioned
drift.

Operator-tier actions = briansrls inline BLOCKING (ci.dag:198
C4-fabrication; ci.dag:120 single-authority-seam) + openai-pro. They
moved the body to: ci.yml is the ratified Workflow carrier under
WorkflowRuntime=YamlStatic via project_github_actions; C4 gated on the
missing v4 Workflow substrate (interim hand-authored bridge until then).
Reconciled the frozen Owns "emission target" + C4 lines from
emit(CiPipeline)/`.dag walks CiPipeline emits YAML` to the
single-authority Workflow-carrier projection; added HEADER RECONCILE
block. C4 operator-ratified INTENT preserved; only projection
mechanism/source corrected, no scope expansion. bootstrap.dag frozen
header preserved verbatim (its "ordered step sequence" I/O contract is
unchanged by the singleton redesign — correct D5 application).
Structural v2-compile gate GREEN (64 modules, 0 diagnostics).

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

* v4 T-24: update HEADER TENSION para to reflect completed D5 reconcile (codex non-blocking nit)

codex (e86a8c4, "no blocking concerns remain") flagged that the
HEADER TENSION paragraph still described the frozen header as unedited
— stale/contradictory after the D5 in-PR reconcile (5f306e2). Updated
the para from "SURFACED, worker does NOT edit frozen lines" to
"RECONCILED in-PR (D5)" pointing at the HEADER RECONCILE block. Comment
hygiene only; no model change. Structural v2-compile gate GREEN (64
modules, 0 diagnostics).

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

* v4 T-24: make CiJob.command faithful + explicitly non-executable (codex BLOCKING)

codex BLOCKING (sha 99753a3): CiJob.command was a lossy paraphrase
("v2-compiler compile --source-root src/v4") while documented as the
command line the deferred interpreter executes — fabricating process
facts (INVARIANTS P1) and not faithfully reproducing the live v4 CI
gate command.

Fix (both options the finding allowed): (a) store the EXACT primary
gate invocation verbatim from .github/workflows/ci.yml
("target/release/v2-compiler compile --source-root src/v4 --output-dir
/tmp/v4-stage1 --target dag"); (b) reframe the field as NON-EXECUTABLE
documentation data — there is no interpreter (process carrier
extdeps/process.dag is T-4.5 scaffold) and a single String cannot carry
a GHA job (the live step is a multi-line shell wrapper + a `cargo build`
prerequisite). The full faithful step + process spawn stay deferred to
extdeps/process.dag (T-4.5) + T-22 (TRACKED SCAFFOLD (3)), explicitly
NOT fabricated into the String. Field doc + CiJob doc + gate-instance
comment updated. Structural v2-compile gate GREEN (64 modules, 0
diagnostics).

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

* v4 T-20: unify fixed-point vocab in body — bit-identical (property) + RoundTrips (AssertKind)

cursor APPROVE_WITH_COMMENTS (non-blocking): body prose said
"`BitIdentical` TestClaim" (implying a kind) in places while the TRACKED
SCAFFOLD correctly ties the deferred check to std/verification.dag
`kind: RoundTrips` (no `BitIdentical` AssertKind exists). One editorial
pass: all BODY occurrences now use "bit-identical" for the
stage1==stage2 PROPERTY and `RoundTrips` for the substrate AssertKind
(Status note, WHY-PINNED-HASH note, FixptStage1Stage2 type comment;
TRACKED SCAFFOLD (2) was already correct). Frozen Owns/Consumes header
lines (22/26/76) preserved VERBATIM — a non-blocking hygiene nit is not
the operator-tier D5 sanction required to edit frozen header lines;
"BitIdentical" there is the property/anchor name, reconcilable with
verification.dag's RoundTrips ("self-host bit-identity") once the body
is consistent. Comment-only; structural v2-compile gate GREEN (64
modules, 0 diagnostics).

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

* v4 T-24: name the fail-closed CiPipeline well-formedness boundary (node.dag Diff #3162 stance)

Addresses briansrls BLOCKING (ci.dag:275): jobs/gates lists + raw
Symbol edges leave missing targets / duplicate ids / needs-cycles
constructible; P2/P4 need a structural OR fail-closed boundary before
consumers land.

Resolved by applying the canonical node.dag Diff #3162 ratification
(not a coin-flip — that precedent settles the shape): ANY jobs/gates
lists are valid CiPipeline DATA; missing-target/dup-id/cycle are NOT
type-level illegal states and there is deliberately NO
ci_pipeline_well_formed eager predicate (exactly the #3162
diff_well_formed anti-pattern). The fail-closed WELL-FORMEDNESS
boundary is the deferred select_jobs consume fold (apply_diff-analogous
all-or-nothing): unresolved/duplicate/cyclic => one fail-closed
Diagnostic (Outcome<T>), decidable via visited-set traversal (P4).
NAMED + OWNED now (select_jobs / lens/affected_set.dag T-21, TRACKED
SCAFFOLD (2)); only its body deferred per scaffold discipline. Doc
tightened in CiPipeline + TS(2). Comment-only; structural v2-compile
gate GREEN (64 modules, 0 diagnostics).

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

* WIP: IB-3 T-20+T-24 workflow/bootstrap.dag + workflow/ci.dag — BootstrapPlan

* v4 T-24: implement eager fail-closed ci_pipeline_well_formed boundary (still-hawk-102 adjudication)

still-hawk-102 (relayed via Lane B) rejected reaffirming #3162 for
CiPipeline: #3162's precondition (no intrinsic well-formedness) is FALSE
here — a job/gate DAG has intrinsic, statically-decidable
well-formedness (unique ids / acyclic / resolving refs), malformed
independent of any consumer; deferring to select_jobs (a consumer) is
ruled out by the operator's "before consumers land". Patterns don't
auto-extend without the per-instance precondition.

Implemented the eager boundary NOW: ci_pipeline_well_formed :
CiPipeline -> Outcome<CiPipeline>, covering (1) unique job ids
(node.dag all_names_distinct CHECK-enforced precedent), (2) reference
resolution (every needs/gate.job resolves to a declared id), (3)
acyclicity via Kahn sink-elimination bounded by count(jobs) passes
expressed as a fold over the finite jobs list (A2 IMPLICIT termination,
INVARIANTS P4) — never an unbounded walk. Any violation = one
fail-closed Diagnostic (AmbiguousIntent, no repair-guess). Structural
Map-for-ids was INFEASIBLE: v4 Map<K,V> is lookup-only (no key
enumeration) so a Map jobs field can't be traversed for the required
acyclicity/ref checks; jobs/gates stay List (fold-traversable) per the
adjudication's "pick by feasibility" + ACCEPTABLE eager option. NOT a
#3162 exception (#3162 never governed this carrier). WELL-FORMEDNESS
header + TRACKED SCAFFOLD (2) rewritten (drop #3162-stance + the
deferral). Structural v2-compile gate GREEN (64 modules, 0 diagnostics).

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

* WIP: IB-3 T-20+T-24 workflow/bootstrap.dag + workflow/ci.dag — BootstrapPlan

* v4 T-20+T-24: de-prose bootstrap.dag + ci.dag in-PR (operator HOLD/audit directive)

Per still-hawk-102 → Lane B directive (HOLD all PRs for operator audit;
de-prose in-PR; load-bearing files keep structured header contract).
Collapsed the review-cycle-accreted body modeling-notes essays to terse
load-bearing comments (CODING.md "default no comments; only non-obvious
WHY"): bootstrap.dag 257→173, ci.dag 508→374. Comment-only — code,
types, fns, data unchanged; structural v2-compile gate GREEN (64
modules, 0 diagnostics).

KEPT (mandated artifacts, not de-prosed): the immutable structured
headers (Scope/Anchor/Owns/A3/Discipline/Consumes/Status/Brief); the
ci.dag D5 HEADER RECONCILE block (#3216 standing rule); TRACKED SCAFFOLD
owner/trigger items; the WELL-FORMEDNESS eager-boundary doc incl. the
Map-infeasibility one-liner (Lane-B-mandated visible) + still-hawk-102
adjudication provenance; ledger-provenance + supersession one-liners;
no-fabrication/single-authority + command-non-executable facts.
REMOVED/COLLAPSED: multi-paragraph restated rationale, defensive
review-cycle elaboration. RELOCATE: n/a (no in-scope target; design
narrative already captured in PR comments + DECISIONS). No D2-alias
prose present (verified — file is not D2-affected, no D2 reconcile).

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

* v4 T-20+T-24: STRICT de-prose bootstrap.dag + ci.dag (still-hawk-102 directive, interim until #3226)

Per still-hawk-102 STRICT DE-PROSE RE-DO (supersedes prior nominal
de-prose; prior attestation not accepted). A de-prosed .dag carries
ONLY: file-path line; terse Scope/Owns/Consumes/Status header; optional
per-carrier Anchor URL; optional one-line per-TYPE concept tag if
non-obvious. Everything else removed. Comment-only — all code, types,
fns, data verbatim-unchanged; structural v2-compile gate GREEN (64
modules, 0 diagnostics).

Comment-% (was → now): bootstrap.dag ~83% → 19.2% (5/26);
ci.dag ~58% → 3.2% (5/156). Both < 20% hard target.

PROCESS RECEIPT / removed-narrative provenance (kept here in the commit
message per directive, NOT in the file):
- ci.dag D5 HEADER RECONCILE (2026-05-17, #3213, D5/#3216, #3190
  precedent): operator-tier BLOCKING review actions (briansrls inline
  C4-fabrication + single-authority-seam; openai-pro confirming) moved
  the body past the frozen Owns/C4 header; it was reconciled IN-PR to
  the single-authority project_github_actions->Workflow seam with C4
  gated on the missing v4 Workflow substrate (interim hand-authored
  ci.yml bridge). C4 operator-ratified intent preserved; only mechanism
  corrected. This narrative now lives only in git history + prior PR
  comments, not the file.
- ci_pipeline_well_formed is the eager fail-closed well-formedness
  boundary (still-hawk-102 adjudication 2026-05-17): #3162 does not
  govern CiPipeline (intrinsic statically-decidable well-formedness);
  structural Map-for-ids INFEASIBLE (v4 Map<K,V> is lookup-only, no key
  enumeration) so jobs/gates stay List + eager predicate checks unique
  ids (node.dag all_names_distinct precedent) + ref-resolution +
  acyclicity (Kahn elimination bounded by count(jobs), A2-IMPLICIT,
  P4-decidable). Architectural rationale belongs in DECISIONS.md (owned
  by operator/#3226), not this file.
- No D2-alias prose present (not D2-affected, not pipeline-stage); no
  gated reconciliations. Branch 0 commits behind origin/main.

HELD for operator audit; not merging (operator squash-merge only).

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

* v4 T-24: ci_pipeline_well_formed also proves gate-id uniqueness (briansrls BLOCKING)

Valid finding (ci.dag:27): CiGate.id is an addressable identity but the
eager well-formedness predicate checked job-id uniqueness only, so
duplicate gate ids were accepted → ambiguous downstream selection
authority (INVARIANTS P2). Same intrinsic, statically-decidable,
consumer-independent well-formedness class the still-hawk-102
adjudication required for jobs.

Fix (code-only; strict-de-prose preserved, ci.dag 2.9% comment):
added ci_gate_id_occurrences + ci_all_gate_ids_unique (mirroring the
job-id check / node.dag all_names_distinct CHECK-enforced precedent) +
a ci_duplicate_gate_id reason symbol, and a gate-id-uniqueness branch
in ci_pipeline_well_formed (duplicate gate id ⇒ fail-closed Rejected).
Structural v2-compile gate GREEN (64 modules, 0 diagnostics).

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

* v4 T-24: fix ci.dag Consumes header drift (std/* → v4.std.*)

cursor APPROVE exploratory nit: terse Consumes header said `std/node,
std/diagnostic` but the actual imports are `v4.std.node` /
`v4.std.diagnostic`. The terse header is now the sole in-file contract
under operator audit, so header precision matters. One-line accuracy
fix; strict de-prose preserved; structural v2-compile gate GREEN (64
modules, 0 diagnostics).

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

* v4 T-20: expand bootstrap.dag four stages as v4 orchestration DATA (operator directive; resolves codex finding-1)

Operator (still-hawk-102 via loyal-wren-802) adjudicated codex #3213
finding-1: bootstrap.dag DOES own/define/source/orchestrate the four
stages now (supersedes the prior minimal-singleton/deferred-interpret
framing). Expanded per directive:

- DEFINE: each stage is a distinct record with real fields (no more
  empty `{}` markers). SeedToStage0/Stage0ToStage1/Stage1ToStage2 carry
  consumes/produces/via; FixptStage1Stage2 carries left/right/via.
- SOURCE: inputs are real Symbol identities — v4_dag_source (the src/v4
  .dag compiler corpus), v4_stage0/1/2_binary, v2_pipeline (the frozen
  seed executor), bit_identical_check. `Consumes: none` → v4.std.node.
- ORCHESTRATE: BootstrapPlan record + canonical bootstrap_plan wiring
  the four stages with concrete consumes/produces in order, as v4 DATA.
- TRIVIAL v2-DELEGATING BODIES (sanctioned): all compile stages'
  executor `via = v2_pipeline` initially; per-stage shift
  delegate-to-v2 → use-v4's-own as v4's pipeline is built (file FILLED
  IN, never replaced). Orchestration is v4 data from day one.

Per-position type distinctness retained (seed slot must be
SeedToStage0, etc.) so cross-position mis-wiring stays type-prevented.
No coproducts introduced (all records) — emoji-tag directive N/A.
Strict de-prose preserved: bootstrap.dag 7.1% comment (5/70), terse
4-line header only. Structural v2-compile gate GREEN (64 modules, 0
diagnostics). HELD for operator audit; in-PR expansion.

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

* WIP: IB-3 T-20+T-24 workflow/bootstrap.dag + workflow/ci.dag — BootstrapPlan

* WIP: IB-3 T-20+T-24 workflow/bootstrap.dag + workflow/ci.dag — BootstrapPlan

* v4 T-24: port v3 CICommand → typed v4 CiCommand carrier (still-hawk-102 fork-2; Option-1 DECISIONS row)

still-hawk-102 fork-2 directive: replace ci.dag CiJob.command:String with
a proper v4 typed command carrier, PORT (not import) of v3
dsl/gunbc/ci.dag CICommand. Faithful re-express (no shape fork):
  type CiCommand = LintCommand | TestCommand
                 | IgnoredTestCommand { test_name: String }
                 | ShellCommand { command: String }
  CiJob.command: CiCommand (was String); v2_compile_gate_job →
  ShellCommand { command: "<verbatim v2-compile invocation>" }.

Coproduct ⇒ per modeling-discipline.md Practice 4/9 + the coproduct-emoji
directive: in-file one-line tag `// 🟡 coproduct dissolution —
DECISIONS.md LB-P4-3213` on `type CiCommand`; full classification ledger
authored as DECISIONS.md Part-6 row LB-P4-3213 (id assigned by
still-hawk-102 Option-1: worker authors provisional, operator ratifies on
audit). Classification 🟡 YELLOW (scaffold): richer source nameable (the
T-4.5 extdeps/process.dag typed Command{program,args,env} carrier + v3
ROADMAP-F12); ShellCommand{command:String} is the bounded interim;
named trigger = T-4.5 typed Command carrier lands. 5 dissolution
patterns tried, recorded in the ledger row.

ci.dag strict de-prose preserved (3.3% comment, <20%). Structural
v2-compile gate GREEN (64 modules, 0 diagnostics). bootstrap.dag NOT
touched — codex F1/F2 reconciliation pending still-hawk-102 (orthogonal).
#3213 HELD for operator audit.

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

* v4 T-20: bootstrap.dag F1/F2 fixes (still-hawk-102 reconciliation; implement, not rebut)

still-hawk-102 reconciled the codex CR — implement (not rebut):

F1 (Practice-3 forward chain): `via: v2_pipeline` kept (sanctioned
executor-is-v2-initially). `consumes` is now List<Symbol> carrying the
prior stage's produced artifact so the orchestration DATA is a chain,
not three independent compiles:
  seed  consumes [v4_dag_source]                       produces stage0
  self0 consumes [v4_dag_source, v4_stage0_binary]      produces stage1
  self1 consumes [v4_dag_source, v4_stage1_binary]      produces stage2
  fixpt left=stage1 right=stage2 via=bit_identical_check

F2 (Practice-7 enumerated-copy): the three identical
{consumes,produces,via} stage types (SeedToStage0/Stage0ToStage1/
Stage1ToStage2) collapsed into ONE `CompileStage { consumes, produces,
via }`. FixptStage1Stage2 { left, right, via } stays its own type (not
collapsed, per directive). Order/multiplicity expressed as fixed named
BootstrapPlan slots (seed/self0/self1: CompileStage; fixpt:
FixptStage1Stage2) — keeps the exactly-3-compiles+1-fixpt fixed shape
(no over-general List reintroduced) while removing the enumerated copy.

No coproducts (records only) — emoji directive vacuous. Strict de-prose
preserved: bootstrap.dag 8.6% (5/58), <20%. Structural v2-compile gate
GREEN (64 modules, 0 diagnostics). #3213 HELD for operator audit.

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

* v4 T-24: export ci_pipeline as fail-closed Outcome (briansrls BLOCKING — non-bypassable boundary)

Valid finding (ci.dag:54): canonical `ci_pipeline` was exported as raw
CiPipeline, so consumers could read it without passing through the
operator-adjudicated eager `ci_pipeline_well_formed` boundary —
bypassing the P2/P3 fail-closed check. Faithful completion of the
still-hawk-102-directed eager-well-formedness boundary (no shape fork,
no directive conflict): the boundary now cannot be bypassed.

Fix: raw construction is internal `ci_pipeline_unchecked: CiPipeline`;
the exported canonical `ci_pipeline: Outcome<CiPipeline> =
ci_pipeline_well_formed(p: ci_pipeline_unchecked)`. Downstream consumers
must handle Produced/Rejected — the eager fail-closed boundary is now
the only way to obtain the pipeline. v2 supports the fn-application
data initializer (verified). Strict de-prose preserved (ci.dag still
<20%); structural v2-compile gate GREEN (64 modules, 0 diagnostics).
Orthogonal to the bootstrap P2/F1/F2 trilemma (routed, pending
still-hawk-102; bootstrap.dag NOT touched). #3213 HELD for audit.

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

* WIP: IB-3 T-20+T-24 workflow/bootstrap.dag + workflow/ci.dag — BootstrapPlan

* WIP: IB-3 T-20+T-24 workflow/bootstrap.dag + workflow/ci.dag — BootstrapPlan

* v4 T-20: bootstrap (b) expose-only-checked — drop consumable bootstrap_plan_unchecked (still-hawk-102 GO)

still-hawk-102 RULING on the openai-pro (heaviest-weight) REQUEST_CHANGES
re-litigating the adjudicated bootstrap-P2: implement (b). (a)
structural per-stage nominal identities FORBIDDEN — do not revert F2
(codex-F2 / Practice-7 stays closed).

(b): removed the named consumable `data bootstrap_plan_unchecked:
BootstrapPlan`; the BootstrapPlan{...} literal is now inlined as the
sole argument to bootstrap_plan_well_formed(p: BootstrapPlan {...}).
The ONLY named export consumers can bind is now `bootstrap_plan:
Outcome<BootstrapPlan>` (the checked carrier) — the consumable-boundary
leak (unchecked raw record had a name to grab) is closed. Mirrors the
ci_pipeline expose-only-checked precedent (Lane-B-PASSED). F1 (forward
consumes chain) + F2 (single CompileStage) intact; no codex-F2
re-trigger; no shape fork.

v2-compiler parses the inlined nested record literal (verified, not
shipped blind); structural v2-compile gate GREEN (64 modules, 0
diagnostics). Strict de-prose intact (bootstrap.dag 4.5%, <20%).
#3213 HELD for operator re-audit.

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

* WIP: IB-3 T-20+T-24 workflow/bootstrap.dag + workflow/ci.dag — BootstrapPlan

* v4 #3213 IB-3: Practice-10 List-op dissolution pass (operator merge gate)

std/collection.dag (T-3) declares zero derived List ops -> zero RED
(nothing to dissolve into in-PR); every hand-rolled generic List
primitive marked YELLOW gated feature: (owner T-3 std/collection.dag,
named missing op + dissolve-on-arrival obligation). Kahn composition
classified GREEN terminal domain-logic (peer of the well-formed
predicates). One terse in-file tag per file (LB-P4-3213 precedent);
full LB-P10-3213 ledger in DECISIONS.md Part 7. #3244 disposition
vocabulary. Structural v2-compile gate: indexed 67 modules, 0 diagnostics.

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

* v4 #3213: ci.dag expose-only-checked — drop consumable ci_pipeline_unchecked/v2_compile_gate_job (operator REQUEST_CHANGES)

Operator (briansrls) BLOCKING: top-level raw ci_pipeline_unchecked:
CiPipeline was a second authority beside checked ci_pipeline,
bypassable by downstream consumers (P2 single-authority / P3
fail-closed). Fix mirrors the operator-accepted bootstrap (b)
expose-only-checked shape: inline the CiPipeline literal (CiJob/CiGate
inlined) as the sole arg to ci_pipeline_well_formed; remove the named
ci_pipeline_unchecked and v2_compile_gate_job composites so the only
consumable pipeline authority is data ci_pipeline: Outcome<CiPipeline>.
Header Owns updated. Structural v2-compile gate: indexed 68 modules,
0 diagnostics.

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

* v4 #3213: ci.dag rename ci_kahn_fixpoint fold param counter->job (CODING.md names-describe-the-mapping)

Recurring multi-reviewer readability observation (cursor 13938
exploratory): the fold's 2nd callback parameter is the folded `jobs`
element, not a counter; `counter` misdescribed the mapping. Renamed to
`job` per CODING.md "names describe the mapping". Semantically inert
(param remains deliberately unused — the fold is the bounded-iteration
driver per LB-P10-3213-KAHN); structural v2-compile gate: indexed 68
modules, 0 diagnostics. Resolves the observation permanently rather
than restating "intentional".

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

* v4 #3213: rewrite LB-P4-3213 ledger to #3244 precision (consumer-gate, landed target)

CORE ruling (still-hawk-102, Option-1 + #3244): reframe LB-P4-3213 as a
valid plan-bound 🟡 with gate kind = consumer: (first meaning-consumer of
typed-command shape, deferred-by-brief, gate CLOSED). process.dag::Command
is the LANDED migration target (#3209), not the meaning-consumer — future
consumer consumes typed Command directly; #3213 does NO migration / NO
local CiCommand parse. Anti-#3250: NOT "no change needed".

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

* v4 #3213: bootstrap.dag — split stage compiler-of-record from executor (self-hosting identity)

codex BLOCKING + 2 BLOCKING-inline (P1/P2): every CompileStage.via was
v2_pipeline, conflating the orchestration executor with the stage
compiler-of-record and making the fixpt (stage1==stage2) check vacuous.

Fix grounded in load-bearing docs:
- STRUCTURE.md:404-405 "Seed used once": v2 produces v4-stage0, then v4
  compiles itself; v2 is never in the loop again.
- SELF_HOSTING.md §meta-circular: stage0 compiles source->stage1,
  stage1 compiles source->stage2, assert byte-identical.

via -> compiled_by (CODING.md names-describe-the-mapping): seed
compiled_by v2_pipeline, self0 by v4_stage0_binary, self1 by
v4_stage1_binary. No executor bridge field — STRUCTURE.md is explicit
that v2 is seed-once, so no "v2 executes every stage" fact exists; the
brief's "v2 is the initial executor" framing contradicted the doc and
the doc wins.

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

* v4 #3213: ci.dag consumes bootstrap seed authority — single-authority fix (P2/Practice 5)

openai-pro 13971 (BLOCKING, at HEAD 52c207b): ci.dag:52 restated the
bootstrap seed action as a raw ShellCommand argv string, a parallel
authority for the seed→stage chain that bootstrap.dag BootstrapPlan.seed
now canonically owns — drift-prone, violates INVARIANTS P2 single-
authority / modeling-discipline Practice 5; the duplication was also
untracked debt (review §6).

Fix (in-PR, structural model only — not the brief-deferred ci.yml
projection / T-22 lane): add typed CiCommand variant
BootstrapStageCompile{produces: Symbol}; the v2_compile_src_v4 job now
references v4_stage0_binary imported from v4.workflow.bootstrap. A real
machine-readable cross-module edge to the bootstrap authority — the raw
argv is removed entirely; BootstrapPlan.seed is the sole source of
truth. No import cycle (bootstrap does not import ci).

Distinct from / orthogonal to CORE-adjudicated LB-P4-3213: that 🟡 is
the ShellCommand{String} raw-argv command-SHAPE decomposition, deferred
to the consumer lane. This is single-AUTHORITY wiring (an invariant),
resolved now. LB-P4-3213 ledger updated to record the resolution.

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

* WIP: IB-3 T-20+T-24 workflow/bootstrap.dag + workflow/ci.dag — BootstrapPlan

* v4 #3213: Practice-9 de-prose — in-file rationale → ≤1-line ledger pointers

cursor 13986 (NON-BLOCKING, APPROVE_WITH_COMMENTS): ci.dag mid-carrier
comment recorded single-authority/P2 rationale as in-file prose
(Practice 9 — rationale belongs in DECISIONS.md, already covered by
LB-P4-3213). Replace with a one-line `// 🟢 single-authority —
DECISIONS.md LB-P4-3213` pointer; strip the same-shape parenthetical
from ci.dag Consumes line and tighten bootstrap.dag compiled_by tag for
consistency. No semantic change.

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

* v4 #3213: Practice-9 — drop bootstrap.dag compiled_by field-prose

cursor 13998 (APPROVE_WITH_COMMENTS): the `// stage compiler-of-record`
field comment is rationale-on-carrier, not an allowed comment class.
The field name + header Scope line already convey the self-hosting
identity; structure speaks for itself. No DECISIONS pointer needed (no
dedicated ledger entry; header already documents seed-once semantics).
No semantic change.

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

* v4 #3213: structurally enforce BootstrapStageCompile single-authority at the CI boundary

openai-pro 14006 (BLOCKING, manual re-review @ 5d4468d): BootstrapStageCompile{produces:Symbol}
took an unconstrained Symbol and ci_pipeline_well_formed never validated it against the
canonical BootstrapPlan outputs — the single-authority seam the ledger claims as resolved
was prose/convention, not structural enforcement (INVARIANTS P2 / modeling-discipline
Practice 5/6).

Fix (structural model, in-scope — not the brief-deferred T-22 executable lane):
- bootstrap.dag owns bootstrap_stage_output(s: Symbol) -> Bool — the single authority on
  the canonical stage-output set {v4_stage0_binary, v4_stage1_binary, v4_stage2_binary}.
- ci.dag imports it; ci_pipeline_well_formed now consumes the bootstrap authority via
  ci_all_commands_authority_ok and fail-closed rejects any BootstrapStageCompile.produces
  outside that set (ci_bootstrap_authority_violation). A dangling payload cannot reach
  Produced — the invariant is enforced at the substrate boundary, not asserted in prose.
- LB-P4-3213 ledger updated: single-authority is now boundary-ENFORCED, not prose.

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

* v4 #3213: ADDRESSED-BY-CONSTRUCTION + plan-bound 🟡 to T-22 (CORE horn (i))

still-hawk-102 ruling (2026-05-18): the BootstrapStageCompile single-
authority seam is addressed-by-construction (pure structural predicate;
out-of-set produces cannot satisfy the gate — modeled Rejected Outcome,
no imperative side-channel; verified in code @6353d695e). Horn (ii)
in-PR executable harness REJECTED (T-22-in-#3213 = brief violation).

Records the deferred executable demonstration as an explicit plan-bound
🟡 with bilateral binding:
- DECISIONS.md LB-T22-3213: arrival (T-22 TestClaim runner) + follow-up
  (negative TestClaims for the bootstrap-stage rejection family) that
  dissolves the 🟡.
- TASKS.md T-22 scope: same obligation, cross-referencing LB-T22-3213
  (neither side vague).
- ci.dag in-file one-line tag → LB-T22-3213.

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

* v4 #3213: Practice-9 — single coproduct tag on CiCommand (drop variant-level 🟢)

cursor 14020 (APPROVE_WITH_COMMENTS): CiCommand carried two emoji
dissolution lines (coproduct-level 🟡 + variant-level 🟢), reading as
conflicting dispositions on one type. Rubric wants one required
🟢/🟡/🔴 tag per coproduct; the LB-P4-3213 ledger already carries the
single-authority/command-shape nuance. Drop the redundant variant-level
🟢 line; the coproduct-level 🟡 tag + DECISIONS.md ledger stand. No
semantic change.

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

* v4 #3213: CI bootstrap-authority consumes bootstrap_plan Outcome, fail-closed (P2/P3)

Operator BLOCKING inline (#3213 ci.dag:168): bootstrap_stage_output
checked static stage-symbol membership {v4_stage0_binary,1,2} instead of
consuming bootstrap_plan: Outcome<BootstrapPlan> — so CiPipeline could be
Produced even when the canonical bootstrap plan is Rejected, bypassing
the fail-closed bootstrap authority (INVARIANTS P2 single-authority /
P3 fail-closed).

Fix: bootstrap_stage_output now takes Outcome<BootstrapPlan>, matches it
— Rejected ⇒ false (fail-closed: CI cannot pass while bootstrap is
Rejected), Produced{value: bp} ⇒ produces ∈ {bp.seed/self0/self1
.produces} (validated-plan actual outputs, not a static set). ci.dag
imports bootstrap_plan and threads it through ci_command_authority_ok →
ci_pipeline_well_formed. The validated bootstrap_plan is now the sole
authority. LB-P4-3213 ledger updated (P2/P3, plan-Outcome consumed).

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

* v4 #3213: add mandatory // Ledger: pointer line to load-bearing workflow headers

CORE ruling (still-hawk-102 via Lane B): the de-prose-vs-rail fork was
FALSE — strict de-prose stands AND one mandatory `// Ledger:` pointer
line per load-bearing file (pointer class, not prose). Adds the
CORE-specified line after Status: in bootstrap.dag + ci.dag. No body
churn; consistent with strict-de-prose (concrete ref pointer, ≤1 line).

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

* v4 #3213: CORE Option B — rescind // Ledger: line, keystone wins (registry doc→files)

CORE ruling (still-hawk-102) on the openai-pro 14070 RC vs the
modeling-discipline.md:503-531 keystone contradiction: the // Ledger:
mandate is RESCINDED — strict de-prose keystone wins (header stays
exactly four lines; no see-docs/X pointer in .dag).

- bootstrap.dag / ci.dag: remove the // Ledger: line (-1 each).
- Registry moves doc→files (Practice 5, top-down): design-pure-bootstrap-zero.md
  names the two load-bearing workflow files + A3/PROOF-1/STOP-rail + C4;
  INVARIANTS.md + src/v3/SELF_HOSTING.md add short Practice-5 registry
  cross-refs. Authority flows doc→files, not per-file upward pointers.

Replays swift-ram-178 a94a312 verbatim onto the #3213 branch.
Clears openai-pro 14070; consistent with the keystone.

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

* v4 #3213: reconcile to authoritative trimmed spec — drop INVARIANTS.md registry para

still-hawk TRIM relay (post-a94a3123f) set the authoritative one-commit
spec = NO INVARIANTS.md edit: registry lives only in
docs/design-pure-bootstrap-zero.md + src/v3/SELF_HOSTING.md + the .dag
// Ledger: strips. 9fda2f0 over-included the INVARIANTS.md para
(replayed from the pre-trim a94a312). Drop it to conform; the two
authoritative registry homes + .dag strips stand unchanged.

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 19, 2026
… spec)

Frames the substrate's read/edit surface for arbitrary code at the
Node level — not the file level. Files are a delivery / persistence
mechanism modeled via extdeps/file_system.dag; the language doesn't
couple to them. Reads target Nodes (and scopes within Nodes); writes
are structural Edits to Nodes; Node-to-File binding is its own
concern, modeled alongside Node, not inside it.

Operator-stated motivation (2026-05-19): the mechanical part of
shifting bits isn't the hard part — the INTERFACE is. This doc
captures the design intent + worked examples + open interface
questions, especially for LLM/agent consumers.

Doc structure:

- §0-1: framing — why node-centric, not file-centric (3 reasons:
  files decoupled from concepts; edits should be structural;
  agent reasoning is at concept level)
- §2: read interface — apply_lens(lens, scope, mode) per QRY-1
  ratification (2026-05-15); no separate query subsystem; lens
  catalog + composition
- §3: write interface — Path/Edit/Diff per #3162 ratification;
  apply_diff fold semantics (all-or-nothing fail-closed)
- §4: read → edit pipeline — six-step closed loop (Read →
  Diagnose → Propose → Gate → Apply → Re-emit). Files only re-enter
  at Re-emit; they're a downstream effect of substrate state.
- §5: three worked examples — (A) bare-alias refactor to canonical-B
  (same shape as #3338); (B) rename a concept across the corpus via
  CanonicalConcept registry cascade; (C) TestClaim breakage
  diagnosis + fix
- §6: six open interface questions — higher-order Edit combinators,
  composition under overlap, intent-shaped declarations (generalized
  Track 2), LLM-targeted diagnostic shape, workflow-as-data for the
  agent loop, structural provenance traces
- §7-8: scope clarifications + status

Status: design spec; mechanical primitives exist, T-23 realizes them;
the six open interface questions are where the substantive interface
design work lives. No implementation prescribed.

This is operator-requested framing work, not action work. Each open
question becomes its own follow-up doc / PR when picked up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request May 19, 2026
* design-dissolution-lens: propose L1.7–L1.12 from 2026-05-18 ingest

Adds six proposed Layer-1 lenses derived from the 2026-05-18 review
ingest against `main@e7b8a8d` (corroborated against worktree HEAD).
Each section follows the existing L1.x format (signature / decidability /
verdict / escape / kills) and includes concrete code-level match cases
+ clean-shape examples, so the structural signature is reviewable
without chasing repo paths.

- L1.7 Off-substrate-fact — prose-asserted facts (F3 lattice, F4 width,
  F11 opacity). Generalizes the standing "machine-readable inhabitance"
  ruling.
- L1.8 Wrong-home — orphan operations (F5 `nat_compare` in float.dag).
  Mechanizes MODELING M9.
- L1.9 Vacuous-arm — exhaustive-but-empty match (F1
  `ComputationNode { behavior: _ } => true`).
- L1.10 String-escape-hatch — typed-model bypass via String (F6
  `ShellCommand { command: String }` vs typed `process.Command`).
  Generalizes L1.6.
- L1.11 Plausible-fallback — fabricated-sibling fallthrough (F10
  `DELETE None => CreateEffect`).
- L1.12 Parallel-authority — unmarked duplicate concept homes (F9
  `dsl/std` vs `src/v4/std`; D2-resolver provisional + planned-absent).

Each carries `Status: proposed` in the section header. Slipped-by
ledger (§8) gains corresponding rows pinned to current main file
locations so the evidence is grep-anchored per §3 methodology.

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

* L1.12 F9 snippet: show existing classification tags, sharpen authority gap

cursor/composer-2 review noted that the F9 "Concrete match" block
implied both `dsl/std/types.dag` and `src/v4/std/logic.dag` were bare,
when both files actually carry annotations above their `type Bool` line
(legacy-scanner anchor prose in dsl/std/types.dag:163-172;
🟢 coproduct-dissolution classification tag at src/v4/std/logic.dag:13).

The lens's case is sharper, not weaker, once the existing tags are
visible: they classify the finding shape (dissolution status, scanner
anchor) but neither *designates authority* between the two parallel
declarations. L1.12 specifically requires a designator that picks a
canonical winner, which is the gap classification tags don't fill.

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

* WIP: PM

* L1.7 / L1.8 / L1.12: tighten hard-gate semantics per codex review

Addresses three BLOCKING findings on the L1.7–L1.12 proposal:

L1.7 — width discharge must be recursive. The previous signature/clean
shape allowed a `Word64 { bytes: List<Byte> where len(_) == 8 }` that
bottomed out at an unconstrained `Byte`, so an arbitrary-bit-count
`Byte` still inhabited a "well-formed" `Word64`. Signature now requires
a recursively-discharged refinement chain down to a fixed-cardinality
leaf or primitive bit; clean-shape example shows the full
Word64 → Byte → Bit chain and structurally distinct Float32/Float64
exponent/significand widths instead of a shared `FloatBody`.

L1.8 — primary-concept selector replaces the argument-files heuristic.
Previous signature ("every argument's type lives in file X") missed
witness-target homing (a `meet` field of `Lattice<T>` belongs with T,
not with whichever file declared its argument types). New four-rule
structural cascade in priority order:
(1) declared witness target → algebra's type parameter is the home;
(2) same-type closure (`fn(T,T)→T` etc.) → T is the home;
(3) upstream argument+return convergence on file X → X is the home;
(4) no single owner → cross-cutting, lens does not fire.

L1.12 — escape valve must be structural, not prose. The previous
"// Authority: canonical | historical" comment markers were prose-
as-authority — exactly the shape L1.7 exists to kill. The lens is now
self-consistent: only structural shapes discharge it — alias/import
identity from historical to canonical, a `data ... :
HistoricalDeclaration` row in a retirement ledger read as data, or
deletion+migration in the same change. Comment markers explicitly do
not satisfy the escape, by construction.

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

* L1.9 / L1.10 / L1.12: remove naming heuristics; substrate-declared facts only

Addresses three BLOCKING findings from codex review on cfbc247:

L1.9 — replace function-name suffix vocabulary with intra-match
asymmetry. The previous signature gated on `*_well_formed` / `*_valid`
suffixes — naming as a structural fact, which violates P1 ("heuristics
are never structurally necessary"). New signature is purely structural:
a single match where ≥1 arm has a trivial-literal RHS AND ≥1 sibling
arm does non-trivial structural work. The discipline-role is inferred
from the fact that the author already wrote real work for some
variants, which makes the trivial siblings a vacuum. The F1
node_locally_well_formed case still fires (TypeNode arm calls
edges_conform, ComputationNode arm returns true).

L1.10 — replace hardcoded `command`→Command / `path`→Path / `url`→Url
field-name table with a substrate-declared canonical-carrier registry.
A typed carrier declares `data X: CanonicalCarrier<X> = { supersedes_string:
{ in_role: <role-tag> } }`; the lens reads the registry. Adding a new
typed carrier is now a `data` row in `extdeps/`, not an edit to the
lens definition. The lens carries no domain names.

L1.12 — split planned-absent-import out of the duplicate-authority
lens. They are different failure shapes: duplicate `type T` in two
files is a duplicate-authority finding; a dangling import path is an
unresolved-reference / fail-closed P3 finding. Collapsing them under
one verdict reports the wrong root cause. L1.12 narrows to
duplicate-declaration; planned-absent moves to an L0.8-extended row in
the slipped-by ledger. The D2-resolver concrete-match block is retitled
as a cross-reference note explaining why it does *not* collapse into
L1.12.

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

* WIP: PM

* L1.10 / L1.12: close opt-in bypass, broaden type-decl signature

codex review on 3fb3e4d raised two valid findings:

L1.10 — the role-tag refinement created an opt-in opportunity for
authors to bypass the typed-carrier rule by omitting the tag. The
escape "no role-tag refinement, passes" was convention-level
enforcement, not API-level. New signature drops the role-tag
mechanism entirely. The CanonicalCarrier registry declares a
`supersedes_string_at_field_named` set (substrate data); the lens
fires on any String field whose name appears in any in-scope
registry entry, unconditionally. The author cannot bypass by omitting
an annotation because there is no annotation — the trigger is the
field name they chose plus the registry-declared coverage. Legitimate
raw-string exemptions move to structural Exemption rows in the same
registry, read as data.

L1.12 — the prior signature said "type T = ..." literally, which only
matches the alias/sum form. The slipped-by ledger row claims coverage
of duplicate machine-word homes, but `type Word64 { bytes: List<Byte> }`
is record form and would have escaped the literal signature. Broadened
to "any `type T` declaration form" — sum/alias, record, unit, generic
— with explicit enumeration of the covered forms so the signature
unambiguously matches the cases in the section's own examples and
ledger.

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

* WIP: PM

* L1.1–L1.6: add Concrete match + Clean shape code examples

The original L1.1–L1.6 sections describe each lens by signature /
decidability / verdict / escape / kills, but did not show what the
matching code or the discharging code actually look like. Adds the
same "Concrete match" + "Clean shape" example blocks the proposed
L1.7–L1.12 sections use, so each lens is concretely readable without
chasing the referenced PRs.

- L1.1: basic discriminant shape (`nat_is_zero`) + the laundered
  constant-algebra fold (`free_monoid_is_empty`-via-fold).
- L1.2: (a) struct-of-functions (`ListMap<A,B>` wrapper) and (b) N
  near-identical single-field structs (`{ spelling: String }` ×N).
- L1.3: declared-but-never-inhabited type (`ParseError` with no
  constructor, no `data`, no alias, no field).
- L1.4: `Outcome<T>` clone (`NormalizeChildrenResult`), with the
  three-variant `Cached | Produced | Rejected` shape as the escape.
- L1.5: clean recursion mirroring data shape (`ci_member` over List)
  and the short-circuit `match acc { Rejected => propagate; Ok =>
  continue }` ladder (resolve/normalize walkers).
- L1.6: type-construction template tables (`list_template: "Vec<{0}>"`)
  vs. structural target-type modeling.

No signature, verdict, or escape semantics changed; this commit only
adds illustrative code blocks.

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

* WIP: PM

* A0 umbrella + cross-cutting themes + L1.6→L1.10 merge

Implements the consolidation feedback as a middle path: tightens the
conceptual scaffolding without dismantling the lens catalog.

- §1: introduces A0 ("every semantic fact must have exactly one
  structural witness") as the umbrella invariant, with A1 retained
  underneath as the operation-specific specialization. Explicitly
  framed as operationalizing modeling-discipline.md Practice 10, not
  as a parallel rulebook, to avoid the L1.12-class parallel-authority
  hazard of duplicating Practice 10's principles here.

- §5.0 (new): adds the three-levels framing (Invariant / Theme / Lens),
  the lens → theme(s) catalog (derive / witness / canonical-home /
  fail-closed), and the explicit disclaimer "themes are explanatory
  tags only — they do not define CI gates, test-corpus boundaries, or
  implementation passes; the mechanically enforced unit remains the
  L1.x lens signature." Per the §3 methodology, each lens's signature
  must be the smallest structural pattern that catches its finding's
  class with zero false positives, so theme-sharing alone does not
  collapse machinery.

- L1.6 → L1.10 merge: the only mechanical merge in this rev, because
  the prior doc already stated that L1.10 generalizes L1.6. L1.10 is
  renamed "Textual-bypass lens" with two sub-signatures:
    L1.10.a TemplateHole       — registry-free, catches `{0}`/`{1}`
                                  positional-placeholder string
                                  literals used as emitters
    L1.10.b CanonicalCarrier   — substrate-declared registry, catches
                                  String fields whose name appears in
                                  a CanonicalCarrier coverage set
  L1.6 section becomes a one-paragraph pointer to L1.10.a, preserving
  anchor compatibility. The slipped-by ledger's F6 row is repointed to
  L1.10.b and a new F8 row is added for L1.10.a.

L1.2/L1.3/L1.4, L1.8/L1.12, and L1.9/L1.11 are intentionally not
merged — their detection machines are mechanically distinct (different
signatures, decidability arguments, escape valves) and the operator
TDD-pairs directive requires distinct test corpora per lens. They
share themes in the §5.0 catalog without sharing implementation.

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

* A0 tightening: witness-path / lens-family / Practice-10 ratification

Five sharpening edits from operator review of the A0/themes pass:

1. A0 rephrased: "exactly one structural witness" → "exactly one
   canonical structural witness *path*". Alias / re-export edges,
   retirement-ledger rows, and derived operations reading the same
   witness all point at one authority; they are the path, not a
   multiplicity that violates A0.

2. §2 "one substrate gap" claim updated. The original sentence was
   true for the L1.1/L1.5 seed findings but too narrow for A0's
   broader territory. Now distinguishes the seed gap (no derived
   discriminant/catamorphism → workers hand-roll them) from the
   general gap (missing witness table / authority map / refinement
   edge / diagnostic carrier → workers encode locally in prose /
   names / strings / duplicate homes / plausible defaults).

3. L1.10 explicitly renamed "Textual-bypass lens family" with an
   "Exception to §5.0" note: L1.10.a TemplateHole and L1.10.b
   CanonicalCarrier are the mechanical units, sharing a finding
   family and reporting label but keeping separate signatures,
   decidability arguments, escapes, and test corpora. Resolves the
   tension between §5.0 ("the mechanically enforced unit is the L1.x
   signature") and L1.10's two-detector structure.

4. L1.6 stub retitled "Deprecated alias — see L1.10.a `TemplateHole`"
   so old test names and slipped-by references remain traceable.

5. §8 trailing prose fixed: "all four are burn-down substrate PRs"
   was true when the ledger had four rows; now it has the four seed
   rows plus the ingest extension. Reframed as "Pattern from the seed
   PR rows" with an explicit note that the ingest rows extend the
   ledger to A0's broader territory.

6. A0/A1 ratification sentence made authority-chain explicit: "Once
   ratified into Practice 10, A0/A1 become citable hard rules; this
   doc remains the enforcement mechanism." Avoids the rulebook-ish
   phrasing that suggested A0/A1 were independently citable.

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

* WIP: PM

* §10 Dependency model — lenses are pipeline stages, not infrastructure

Adds a new §10 (renumbering audit to §11) answering the "how does
this run / is it parallelizable / how much work" questions
operationally. The core framing: there is no "lens framework"
separate from the compiler pipeline. Lenses are .dag stages that
declare consumes: edges against the existing parse/resolve/infer
producers, and the compiler's stage-ordering schedules them
automatically.

- §10.1: shared-indices taxonomy — maps each shared structural fact
  (AST, symbol resolution, variant lists, inhabitance edges, witness
  registries, refinement clauses, import graph, fail-closed return-
  type carriers) to the existing pipeline stage that produces it and
  the lenses that consume it. Most of what lenses need is already
  computed; lenses just query.

- §10.2: three small derived stages cover what the existing pipeline
  doesn't yet expose — match_arm_shape (reusable by L1.1, L1.9,
  L1.11, L0.7, L0.13), closed_vocab_scan (L1.7), concept_home (L1.8).
  Each is a single deterministic fold; reusable across multiple
  lenses by design.

- §10.3: a lens is just another .dag stage with declared dependencies.
  Adding a lens = land a stage; the existing compiler stage-ordering
  handles scheduling. No new framework.

- §10.4: per-file and per-lens parallelism fall out of the dependency
  graph automatically; affected_set integration scales CI cost with
  PR size, not corpus size.

- §10.5: summary of operational properties — one dependency model
  across pipeline + lenses, lens addition = stage land, index
  addition = small derivation stage shared by all lenses that need
  it, self-application clean (the compiler enforces the discipline
  it follows).

This is the L1.12-class self-consistency check: a separate "lens
framework" with its own dependency model would itself be parallel
authority, which the lens suite exists to kill. The dependency-model
section makes explicit that the lens framework reuses the pipeline's
existing modeling — one dependency system for everything.

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

* design-dissolution-lens: stabilize #3313 — L1.11/L1.12 fixes + canonical L1.x keys

Bundles three changes operator-routed via witty-cat-59 as the #3313
stabilization trigger:

1. **L1.11 plausible-fallback** — drop the "return type is not
   Outcome<_>" carve-out that was a false negative on
   `fn(...) -> Outcome<T>; None => Produced { value: ... }`.
   Replaces with a structural FailClosedDiagnostic registry
   declaring Outcome::Rejected as the registered fail-closed
   constructor. The lens fires on RHS Ctors that are not registered
   as fail-closed, covering both the F10 bare-return case AND the
   Outcome-wrapped fabricated-success case the prior signature
   missed. or_default-style total-by-design helpers escape via a
   structural PlausibleFallbackExemption row, same shape as L1.8
   WrongHomeExemption and L1.9 VacuousArmExemption — no comment
   anchors.

2. **L1.12 parallel-authority** — reframe so lexical-name collision
   is the *trigger* (not the conclusion), with four resolution paths
   the lens checks against the substrate:
   (1) same-concept-with-alias (CanonicalConcept row + alias edge) →
       passes
   (2) same-concept-without-alias (CanonicalConcept row but no alias)
       → fires (the original duplicate-authority case)
   (3) distinct-concepts (ConceptDisambiguation row marks them as
       legitimately different) → passes
   (4) silence (no row in either registry) → **fires as
       unresolved-duplicate**
   The prior formulation only fired on (2) and missed (4) — the F9
   motivating case where Bool was declared in two files with no
   CanonicalConcept row anywhere. The substrate must take a position
   on every cross-file lexical collision; silence fails closed.

3. **§5.1 Canonical L1.x acceptance-key names** — new subsection
   enumerating the stable canonical key names downstream consumers
   (e.g. coverage.dag's dissolution_l1_* rows) must use. The lens
   suite is the single authority; downstream key sets are
   projections. Includes explicit migration notes:
   - `dissolution_l1_6_emit_template` → retired, no L1.6 key
   - `dissolution_l1_10_string_escape_hatch` → split into
     `dissolution_l1_10_a_template_hole` AND
     `dissolution_l1_10_b_canonical_carrier`

This is the #3313-stabilization step in #3322's closeout register
(item 7). On land:
- warm-koi-304's #3318 (held-at-track-not-finalize) can rebase
  against the stable §5.1 enumeration
- batch-(d) remains held until A1 invariant placement PR lands too

Routed via witty-cat-59 (program-coordination); follow-up PR owned
by sunny-wolf-435 as #3313 author per #3322 closeout-register row 7.

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

* L1.12 wording: "three resolutions" → "four outcomes (three passing + silence)"

cursor/composer-2 review noted editorial inconsistency: the text
said "exactly one of three resolutions" but the list enumerated
1-4 with silence as case (4). Corrected to "one of four outcomes —
three passing resolutions plus a fail-closed silence case" so the
prose matches the structural enumeration that follows.

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

* L1.12: close the decision table — five outcomes, all in-table

Reviewer (briansrls 2026-05-18T23:26Z) flagged that the prior wording
said "three passing resolutions" but the enumerated 1-4 list had only
TWO passing (alias, ConceptDisambiguation) and TWO firing
(same-concept-without-alias, silence). The HistoricalDeclaration
retirement-ledger and deletion/migration paths from the Escape section
were "outside the stated decision table" — a P2 decidable-single-
authority violation.

Fix: restructure the enumeration to cover ALL mechanically-distinct
outcomes inline, so the decision table is closed:

  (1) Same-concept-with-alias                  → passes
  (2) Same-concept-with-retirement-record      → passes  (new: was in Escape)
  (3) Distinct concepts (ConceptDisambiguation) → passes
  (4) Same-concept-without-alias-or-retirement → fires (original duplicate-authority case)
  (5) Silence                                   → fires (unresolved-duplicate)

Three passing + two firing = the arithmetic now matches. Deletion /
migration is explicitly noted as "not a fifth resolution" — it removes
the trigger condition entirely (no lexical collision), so the lens
never engages, which is mechanically distinct from a resolution.

The Escape section is collapsed to a pointer at outcomes (1)/(2)/(3)
to avoid duplicating the decision-table content.

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

* L1.12 Decidable bullet: include HistoricalDeclaration registry

Closes the residual gap on the wrap BLOCKING review: outcome (2)
"Same-concept-with-retirement-record" consults a HistoricalDeclaration
registry row, but the prior Decidable bullet listed only
CanonicalConcept + structural-alias + ConceptDisambiguation. Now every
registry the 5-outcome decision table consults is named in the
decidability statement explicitly.

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

* WIP: PM

* L1.11 Verdict: per-case fix guidance (bare-return vs Outcome-wrapped)

cursor/composer-2 review caught a contradictory-guidance bug: the new
L1.11 bullets explicitly include the Outcome-wrapped case
(fn(...) -> Outcome<T>; None => Produced { value: ... }) as firing,
but the Verdict still said "lift the return type to Outcome<T> and
return Rejected" — which doesn't address the case that's already
Outcome-wrapped.

Split the fix into two case-specific guidances:
- Bare-return case: lift return type to Outcome<T>, return Rejected.
- Outcome-wrapped case: replace Produced ctor with Rejected
  { diagnostic: DerivationUnknown } on the missing-info arm.

Same underlying fix shape (escalate missing info through the
registered fail-closed-diagnostic variant) — just two distinct
starting points depending on which form of fabricated-success the
lens caught.

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

* L1.12: restore concept-level detection via two-trigger union (lexical OR CanonicalConcept co-membership)

codex review (REQUEST_CHANGES) caught a real semantic weakening in
the prior "lexical collision is the trigger" rewrite: two parallel
homes for ONE concept with DIFFERENT names would slip past the lens
entirely, contradicting P2 / Practice 5's concept-level
single-authority demand.

Fix: restore concept-level detection by adding Trigger B (concept-
graph) alongside the existing Trigger A (lexical). The lens fires on
parallel authority detectable in EITHER way:

- **Trigger A (lexical):** cross-file `type T` declarations sharing
  a simple name. (Existing; catches the F9 motivating case.)
- **Trigger B (concept-graph):** two `type T1` / `type T2`
  declarations in different files that are co-members of a
  `CanonicalConcept` row, regardless of whether their lexical names
  match. (NEW; catches the same-concept-different-name case the
  prior rewrite missed.)

Either trigger enters the same 5-outcome resolution table.

Per-outcome under Trigger B:
- (1) alias / (2) retirement-record / (4) no-resolution apply
  cleanly to both triggers
- (3) ConceptDisambiguation under Trigger B would CONTRADICT the
  CanonicalConcept co-membership row — registry-inconsistency,
  caught by L0-class checks, not L1.12
- (5) silence is NOT reachable under Trigger B (the trigger IS a
  registry row's presence); only reachable under Trigger A

Also added an explicit Decidability Boundary note: the lens cannot
catch the case where two homes use different names AND no
CanonicalConcept row registers them as the same concept. That's a
P2 violation but mechanically undetectable from parsed substrate
alone — closing it requires either operator judgment or a future
structural-similarity-fold primitive. Per §3 methodology, lens
signatures catch their class with zero false positives;
Trigger B's CanonicalConcept-driven gate is the structural surface
decidable today.

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

* WIP: PM

* docs(design): read/edit pipeline — node-centric agent surface (design spec)

Frames the substrate's read/edit surface for arbitrary code at the
Node level — not the file level. Files are a delivery / persistence
mechanism modeled via extdeps/file_system.dag; the language doesn't
couple to them. Reads target Nodes (and scopes within Nodes); writes
are structural Edits to Nodes; Node-to-File binding is its own
concern, modeled alongside Node, not inside it.

Operator-stated motivation (2026-05-19): the mechanical part of
shifting bits isn't the hard part — the INTERFACE is. This doc
captures the design intent + worked examples + open interface
questions, especially for LLM/agent consumers.

Doc structure:

- §0-1: framing — why node-centric, not file-centric (3 reasons:
  files decoupled from concepts; edits should be structural;
  agent reasoning is at concept level)
- §2: read interface — apply_lens(lens, scope, mode) per QRY-1
  ratification (2026-05-15); no separate query subsystem; lens
  catalog + composition
- §3: write interface — Path/Edit/Diff per #3162 ratification;
  apply_diff fold semantics (all-or-nothing fail-closed)
- §4: read → edit pipeline — six-step closed loop (Read →
  Diagnose → Propose → Gate → Apply → Re-emit). Files only re-enter
  at Re-emit; they're a downstream effect of substrate state.
- §5: three worked examples — (A) bare-alias refactor to canonical-B
  (same shape as #3338); (B) rename a concept across the corpus via
  CanonicalConcept registry cascade; (C) TestClaim breakage
  diagnosis + fix
- §6: six open interface questions — higher-order Edit combinators,
  composition under overlap, intent-shaped declarations (generalized
  Track 2), LLM-targeted diagnostic shape, workflow-as-data for the
  agent loop, structural provenance traces
- §7-8: scope clarifications + status

Status: design spec; mechanical primitives exist, T-23 realizes them;
the six open interface questions are where the substantive interface
design work lives. No implementation prescribed.

This is operator-requested framing work, not action work. Each open
question becomes its own follow-up doc / PR when picked up.

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

* WIP: PM

* WIP: PM

* design-read-edit-pipeline: fix two P2 / THESIS-narrowing findings from openai-pro RC

openai-pro (gpt-5-5-pro) review on f15b2b0 flagged two valid issues:

**Finding 1: affected_set as implicit third scope (P2 violation).**
§2 said "frontier is itself a scope" and §5/§6 examples passed
`affected_set(dag, diff)` as `NodeScope(affected)`, but the ratified
SectionRef is two-branch only (DeclarationScope | NodeScope).
Treating `Witness<ReExecFrontier>` as a NodeScope-compatible value
is an implicit coercion the typed surface doesn't model — violates
P2 illegal-states-unrepresentable.

Fix: clarify §2 that the frontier is a SET of declaration/node refs
the caller folds over by re-applying the lens at each member's
existing DeclarationScope/NodeScope. Rewrite all five affected
worked-example sites (Examples A + 6.3 + 6.6) to fold over
`affected.frontier.for_each(ref => apply_lens(_, ref, Enforce))`
instead of passing `NodeScope(affected)`. SectionRef stays
two-branch; gating over the affected frontier is composition, not a
new scope shape.

**Finding 2: workflow/agent_loop.dag conflicts with THESIS narrowing
(LOCKED DESIGN DECISIONS).**
§7.5 proposed extending self-application to `workflow/agent_loop.dag`,
but THESIS retracted meta-process / work-direction modeling on
2026-05-15; self-application is narrowed to gunbc's own build/CI
pipeline (workflow/{bootstrap, ci} only). The reviewer correctly
noted my open question would reopen exactly the surface THESIS
removed.

Fix: reframe the open question per the reviewer's "out-of-scope /
user-program workflow" option. The agent loop is a USER PROGRAM
composing substrate primitives (apply_lens, apply_diff, affected_set,
emit) — not an extension of gunbc's workflow/ surface. Renamed §7.5
from "Workflow-as-data for the agent loop" to "Agent-loop composition
at the user-program level" and explicitly stated `workflow/agent_loop.dag`
is not the right place; THESIS narrowing stands. The substantive open
question (what user-program-side carriers ship with gunbc as
conveniences vs are user-program-authored) is preserved without
reopening the locked surface.

§6.6 (CLI-driven concept declaration hero case) cross-reference also
updated to call it out as a user-program composing primitives, not
gunbc self-application.

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

* design-read-edit-pipeline: honest accounting of Node→File binding gap

openai-pro BLOCKING inline at line 33 (sha c431266) flagged that
the doc overclaimed file_system.dag's coverage: it models POSIX file
operations (open/read/write/close) but does NOT yet carry a Node→File
rendering binding as a first-class substrate fact. The relationship
is currently emergent from the emit stage, not stored as queryable
substrate data — claiming "file-tying is a structural fact" left the
central file-binding authority off-substrate.

Fixes:

1. **§1 rewrite (lines 41-44)**: replace the overclaim "the substrate
   models File explicitly ... so file-tying is a structural fact"
   with an honest accounting: file_system.dag is POSIX ops only; the
   Node-to-File relationship is currently emergent from emit, NOT a
   queryable data row. Design intent is right (file-tying as
   substrate data so it's queryable and auditable, not implicit in
   emit behavior), but the primitive doesn't exist yet. Tracked as a
   §6.8 gap.

2. **§6.8 addition (item 6)**: add Node→File binding registry to the
   missing-substrate list. Concrete shape:
   `data <node>_rendered_into: NodeToFileBinding = { node, file, region }`.
   Closes the "files are a downstream effect of substrate state"
   framing — that effect becomes a structurally-recorded fact, not
   just a compile-time side effect.

The design intent (node-centric, file-as-effect) survives intact; the
honest update is that one of the substrate primitives needed to make
it fully structural still has to land. That's the right shape per
INVARIANTS P2 (illegal-states-unrepresentable / single authority):
don't claim a structural fact that isn't yet stored as queryable
data — name the gap as a tracked dependency.

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

* design-read-edit-pipeline: mirror ratified Edit definition exactly (replacement only)

openai-pro BLOCKING inline at line 81 flagged that the doc's
description of Edit as "Replace / insert / delete at a position"
contradicted the ratified std/node.dag authority, which defines:

  type Edit { at: Path, replacement: Node }
  type Diff { edits: List<Edit> }
  type Path { steps: List<Symbol> }

Edit is a SINGLE replacement at a Path — no separate insert / delete
variants. The "Replace / insert / delete" prose introduced operations
the ratified type doesn't model, violating P2 single-authority.

Fix: replace the prose with the exact ratified shape, noting that
insertions and deletions are expressed by replacing the parent node
with a new parent whose children list includes / excludes the
targeted child. This is the natural decomposition under the
ratified single-Edit shape and avoids inventing a parallel contract.

Same single-authority fix shape as the earlier SectionRef +
apply_diff alignments — point at the ratified definition rather than
restate with diverged wording.

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

* design-read-edit-pipeline: mark §5/§6 examples as future-combinator-layer pseudo-code

codex BLOCKING review (sha:1dcf5193) wrap raised three findings; two
were already addressed in prior commits (c431266 affected_set scope
collapse + ab4bcdb Edit shape mismatch). The third is the worked
examples using higher-level edit verbs (replace_with, replace, insert,
insert_field) that don't map directly to the ratified
Edit { at: Path, replacement: Node } shape.

Per the reviewer's "either express as replacement-at-path rewrites or
mark them as a future combinator layer" binary: chose mark-as-future-
combinator-layer because the examples are illustrative intent shapes,
not authoritative Edit constructors. Rewriting each into explicit
parent-replacement decomposition would make the examples much longer
and harder to read for the design intent they're meant to convey.

Added a clear pseudo-code disclaimer at the top of §5 ("worked
examples") that covers both §5 and §6 examples:

- States the verbs (replace_with, replace, insert, insert_field) are
  future-combinator-layer shorthand, NOT literal .dag
- Cites §3 for the ratified Edit { at: Path, replacement: Node }
- Explains the decomposition: insertions/field-additions land as
  parent-replacement (build a new parent node whose children list
  includes the desired child, single Edit at parent_path)
- Points at §6.8 items 1 + 3 (machine-readable Clean shape +
  DAG-of-edits composition) as the substrate work that builds the
  combinator layer
- "Treat the examples as intent illustrations, not authoritative
  Edit constructors"

This restores single-authority discipline: §3 names the ratified Edit
shape, and the examples are explicitly framed as combinator-layer
pseudo-code that compresses common intent shapes for readability.

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

* WIP: PM

* design-read-edit-pipeline: candidate-state gating + grounded L1.12 transform

openai-pro REQUEST_CHANGES on b26f0d8 raised two valid design-level
defects, both blocking:

**Finding 1 — gate/apply ordering bug** (P3 fail-closed / structure
gates emission). The §4 pipeline was:
  4. Gate on affected_set (pre-edit graph)
  5. Apply diff
That gates the PRE-edit state then applies the Diff, letting a Diff
introduce post-edit invariant violations that never get enforced
before re-emit. Violates THESIS:13-15 + :453-457 "compiler validates
every causal link before emitting to targets."

Fix: rewrite §4 as a SEVEN-step candidate-state pattern:
  1. Read
  2. Diagnose
  3. Propose Diff
  4. Candidate: candidate_dag = apply_diff(dag, Diff)   # uncommitted
  5. Gate: enforce lenses against the CANDIDATE state
  6. Commit: dag := candidate_dag (only if every gate passed)
  7. Re-emit
Added explicit "Why gate the candidate, not the pre-edit graph"
paragraph naming the semantic gap the prior ordering would have
created. The "fail-closed promise honest" framing: validation
happens against the state that will be emitted, not against a state
already known to be valid.

Updated worked examples (§5.A, §6.3 catamorphism pipeline, §6.6
CLI pipeline) to use the candidate-state ordering throughout —
apply_diff to candidate, gate against candidate, commit if green.

**Finding 2 — L1.12 transform with ungrounded canonical-home pick.**
§6.4 L1_12_transform called `pick_canonical_home(matched_pair)` in
the outcome (5) silence case (no CanonicalConcept row anywhere).
That's ungrounded inference — picking which side is canonical when
the substrate has no canonical authority declared. INVARIANTS:31-32
says missing facts should be authored, not inferred by shortcuts.

Fix: rewrite L1_12_transform to branch on outcome:
- **Outcome (4)** same-concept-without-alias-or-retirement: a
  CanonicalConcept row EXISTS; READ canonical_home from it. Auto(Diff).
- **Outcome (5)** silence: no canonical authority declared.
  NeedsDecision { because: no_canonical_authority, needs:
  operator_authors_CanonicalConcept_row { candidates: pair } }.
  Never an inferred pick.

Added the general pattern statement: "transforms ground in
substrate-declared authority; absence of authority becomes
NeedsDecision, never an inferred guess." This is the design rule
for every L1.x transform — auto-fix only when the substrate gives
you grounded structural facts to fix toward.

Both fixes preserve the design direction and tighten it on the
fail-closed-and-no-inferred-authority discipline the project thesis
demands.

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

* design-read-edit-pipeline: add hero case (f) — mechanical refactor

Operator-articulated hero case (2026-05-19): mechanical refactors —
declarative model-A → model-B transitions across the corpus — are
"a good use case for more mechanical things (i.e. the only judgement
applied is in which command to run, not literally changing each
line)." Adds §6.7b as the sixth hero case, between merge-sort
synthesis (§6.7) and the missing-substrate enumeration (§6.8).

Key positioning:

- **Cleanest convolution shape** — judgment at command-selection,
  zero per-site judgment. Distinguished from the other cases:
    (a) one lens auto-fix
    (b) one lens with conditional outcomes
    (c) per-site conditional cascade
    (f) declarative target, uniform per-site application

- **Substrate guarantees** — uses the §4 candidate-state pattern to
  give the atomicity guarantee the user asked about ("how can we
  guarantee a successful migration"): either complete or no-op,
  never a half-migrated state. LOC count is irrelevant; the
  substrate handles 10 sites or 10,000 the same way.

- **Affected-LOC enumeration** — pre-execution preview of
  site_count + exact_paths + re_exec_scope, structurally, not by
  grep. Direct answer to the user's "what are all the affected LOC"
  question.

- **Composes per-lens transforms from §6.2** — a mechanical refactor
  often decomposes into per-lens auto-fixes from the L1.x catalog.
  Canonical-B decomposes into L1.7 transforms + L1.12 outcome (4)
  transforms. Agent picks the named refactor; substrate composes the
  per-lens transforms that implement it.

- **PR #3338 as the worked example** — canonical-B across 6
  languages + 7 v3 ratchet dissolutions, two operator decisions
  ("use decl-ref for Bool" + "dissolve the 7 v3 ratchets") plus 13
  uniform per-class site applications. Hand-executed in #3338; the
  substrate (had it been operational) could have applied the entire
  refactor mechanically from those two decisions.

§6.9 recommended ordering updated: (f) mechanical refactor slots
between (b) L1.12 and (c) interface cascade — it's the most directly
useful hero shape for day-to-day refactoring work, and demonstrates
the composition pattern that the agent-shape cases (c)/(d)/(e)
build on.

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

* WIP: PM

* design-read-edit-pipeline: fix §6.10 RootScope slip — use the §2 corpus-fold idiom

cursor/composer-2 review caught a slip: §6.10 wrote
`auto_fix_for_lens(L1.5, RootScope)` while §2 (lines 74-77) explicitly
rules out RootScope as a scope variant ("no separate RootScope /
corpus-wide variant — corpus-wide application is achieved by
composition over the declaration set").

Replaced the RootScope call with the explicit fold over
`declarations_in(dag)`:
  declarations_in(dag).for_each(d =>
    auto_fix_for_lens(L1.5, DeclarationScope(d))
  )

Added clarifying sentence: "auto_fix_for_lens itself takes a
SectionRef (DeclarationScope or NodeScope) — never an invented
RootScope." Keeps the doc internally consistent on the single
structural scope vocabulary per INVARIANTS P2 / Practice 5.

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

* design-read-edit-pipeline: track L1.12 concept-identity carriers as §6.8 item 8 + §6.4 dependency caveat

codex BLOCKING (sha:77469d84) raised two findings; one valid, one
factually wrong.

**Finding 1 — valid.** L1.12 concept identity depends on undeclared
registry carriers (CanonicalConcept, ConceptDisambiguation,
HistoricalDeclaration). Verified absent from src/v4/std/*.dag,
src/v4/lens/*.dag, src/v4/extdeps/*.dag — they only exist as design
in docs/design-dissolution-lens.md (PR #3334, operator manual-merge
queue), not as ratified .dag substrate.

Fix:
- Added §6.8 item 8 explicitly tracking the L1.12 concept-identity
  carriers as missing substrate (alongside item 1 machine-readable
  Clean shapes, item 2 ConditionalDiff ADT, etc.). Lists the three
  carrier shapes and notes the design-pending status.
- Added a dependency caveat callout at the top of §6.4 hero case (b)
  pointing at §6.8 item 8 so a reader hitting the example sees the
  carrier-not-yet-substrate dependency immediately.

Finding 2 — factually wrong (rebutted on-PR, not in this commit).
THESIS.md:232 explicitly carries the retraction with the
"operator-ratified 2026-05-15" stamp.

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

* design-read-edit-pipeline: add §5 Example B dependency caveat matching §6.4

Same finding fired again at line 255 of pre-fix sha (§5 Example B
"rename a concept across the corpus", which also references
CanonicalConcept). The global §6.8 item 8 + §6.4 inline caveat from
07d862f cover the case, but a reader entering at §5 Example B
should see the dependency callout immediately — same shape as the
§6.4 callout. Both inline caveats point at §6.8 item 8 as the global
tracking entry.

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

* WIP: PM

* design-read-edit-pipeline: candidate root explicit in gate surface + LOC rename

openai-pro REQUEST_CHANGES on f3d146b raised two valid design-level
findings; both addressed.

**Finding 1 — candidate authority not typed into gate surface.**
The candidate-state pattern from earlier was correct in intent, but
the worked examples called `apply_lens(_, ref, Enforce)` with a bare
ref — leaving the candidate-vs-pre-edit context to a prose comment
("evaluated in candidate_dag context"). A worker following the
pseudo-code could accidentally enforce against the wrong root.

Fix: introduce `scope_in(root: Node, ref: NodeRef) -> SectionRef`
as the helper that **explicitly binds a frontier ref to a dag root**.
Updated §4 pipeline + §5 Example A + §6.3 catamorphism + §6.6 CLI +
§6.7b mechanical refactor — every gate call now reads
`apply_lens(_, scope_in(candidate_dag, ref), Enforce)`. The candidate
root is structurally visible in every call; can't be lost via
comment-level convention.

**Finding 2 — "affected LOC" reintroduces file/line authority
before Node→File binding exists.**
§6.7b promised "affected LOC" structurally — but §1 explicitly says
file/line is emergent-not-substrate. Promising LOC enumeration
before the Node→File binding registry (§6.8 item 6) is built
contradicts the node-centric framing.

Fix: rename §6.7b "Affected-LOC enumeration" → "Affected-structural-
paths enumeration"; the inline preview computes structural Paths,
not file:line. Added a callout explicitly tying the LOC translation
to the Node→File binding registry (§6.8 item 6) — until that
registry lands, the substrate-native answer is in terms of Paths.
LOC is the downstream projection of "affected sites" via emit's
mapping; the substrate-native fact is "affected structural sites."

Also updated the "guarantee is structural" close-out: "LOC count is
irrelevant" → "Site count is irrelevant." Keeps the doc consistent
that the substrate-native unit is the Path/site, not LOC.

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

* design-read-edit-pipeline: fix §6.10 auto_fix_for_lens straggler — scope_in everywhere

codex APPROVE_WITH_COMMENTS caught one remaining apply_lens call site
I missed in the prior candidate-authority pass: §6.10 auto_fix_for_lens
workflow at line 851 still used `apply_lens(lens, ref, Enforce)` with
the bare ref. Fixed to `apply_lens(lens, scope_in(candidate_dag, ref),
Enforce)` matching §4's "candidate root explicit in the gate surface"
rule and the rest of the worked examples.

Verified: only remaining `apply_lens(_, ref, Enforce)` in the doc is
the §4 anti-pattern call-out itself (explaining what NOT to do). All
actual call sites are consistent.

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 20, 2026
…olf-435 review)

Major doc amendment integrating the substantive review from PR #3437's
sister doc (sunny-wolf-435 PM, against docs/design-read-edit-pipeline.md
which merged in PR #3364 on 2026-05-19).

Reviewer feedback was that the compiler-architecture doc had a substantial
gap: it covered the COMPILE direction (text/data → target) thoroughly but
was silent on the EDIT direction (CoreNode + Diff → CoreNode'), the
read/edit pipeline merged in PR #3364, and the closely-related question
"how will the compiler edit itself / regenerate stage0?"

CHANGES:

1. NEW "Load-bearing references" section (after "What this document is"):
   Comprehensive list of foundational + adjacent ratified design docs the
   compiler architecture composes with. Includes THESIS / MODELING /
   modeling-discipline / INVARIANTS / TASKS as foundational, and 11
   adjacent design docs (read-edit-pipeline, emit-stage-l25, infer-stage-l25,
   lens-application-surface, lens-framework, affected-set-lens,
   dissolution-lens, v4-close-interrogation, v4-dag-rationale,
   pure-bootstrap-zero, substrate-lambda-calculus-grounding,
   bootstrap-fact-model) plus 6 lens-specific design docs.

2. NEW 9th substrate primitive: apply_diff
   - Path / Edit / Diff vocabulary ratified in PR #3162 (std/node.dag)
   - apply_diff scaffold in lens/application.dag (T-23)
   - The substrate is read/write-symmetric: reads via fold_node /
     apply_lens; writes via apply_diff
   - Primitive set is now 9 things (was 8); TL;DR + tally line updated

3. NEW "The EDIT direction — symmetric to compile" section:
   - Read/edit primitives table (Path, Edit, Diff, apply_diff, subterm_at,
     apply_lens, affected_set)
   - The seven-step read→edit pipeline from PR #3364 § 4
   - Candidate-state pattern: gates run against apply_diff(dag, Diff),
     NOT the pre-edit graph. Same monotonic-facts invariant as P3's
     facts-flow-forward, applied to mutation.
   - EDIT direction = the "Query-driven rewrite" ingest path (cross-link
     to the ingest paths table)
   - Library-first agent surface (per read/edit doc § 6.10) — extended
     to apply to compile() too
   - Lens as (find, transform) convolution view; cross-ref to mechanical
     refactor hero case (f) in read/edit doc § 6.7b

4. NEW "Self-modification, stage0, self-edit" section addressing the
   reviewer's specific question:
   - Compiler reads its own source as CoreNode (same lens surface as
     user code; no special introspection)
   - Compiler writes to its own source via apply_diff (two paths:
     hand-authored Diff or mechanical-refactor lens)
   - stage0 regeneration is compile(self, dag, TranslateTo(rust)) — no
     special mode; the homomorphism mechanic applies identically
   - Candidate-state for self-modification safety — lenses gate the
     candidate; compiler cannot break itself silently
   - Implications: no new substrate needed; self-hosting is one specific
     compile invocation; hand-Rust-to-zero IS the loop closing.

5. Glossary expanded with Path / Edit / Diff / apply_diff / apply_lens /
   SectionRef / scope_in / candidate-state pattern / affected_set /
   self-edit-stage0 vocabulary.

The compile + edit directions are now both represented in the doc.
The two designs (this one + read/edit pipeline) compose cleanly — same
CoreNode, fold_node, Diagnostic substrate; the read/edit doc owns the
agent-surface mechanics, this doc owns the homomorphism architecture,
both are the same nine substrate primitives at different angles.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request May 20, 2026
Findings on PR #3437 from codex 2026-05-20T05:24:15Z, all addressed in this
commit:

FINDING 1 — Validate-then-compile gate not type-enforced.
P3 commitment 6 said the project-mandatory wrapper preserves the "by
construction" guarantee, but that was convention, not type-level enforcement.
Updated to require Validated<Output>-style carrier discharged only by the
wrapper; bare compile() now explicitly marked as internal/non-terminal
(accessible to advanced consumers — lens framework, build tooling, self-edit
— but NOT the everyday user surface). The wrapper-as-terminal pattern is
invariant at the type level.

FINDING 2 — Substrate inventory verifiability.
The reviewer flagged "live-substrate inventory was not verified against the
v4 tree." Verified refinement.dag IS on main (1143 bytes, status "T-25-core
modeled" — landed via #3354); the doc claim was correct. Added a
"Verifiability note" pointing at the verification commands (ls + head -10)
+ added commit refs (#3354 for refinement.dag, #3162 for Path/Edit/Diff
vocabulary, #3436 for in-flight T-8 PR) so future reviews can verify
independently. Also added lens/application.dag and lens/affected_set.dag
to the inventory (they were missing).

FINDING 3 — Scaffold-vs-design divergence.
The reviewer correctly identified that the compiler scaffolds in
src/v4/compiler/ predate this doc's ratifications and have divergent
signatures (00_compile.dag's `compile(Source, TargetModel) -> TargetSource`
vs this doc's `compile(CoreNode, LanguageModel, CompileMode) -> Outcome<Output>`,
04_infer.dag's `v4.lens.cost` import vs P3's no-named-lens rule, etc.).
Added a "Scaffold-vs-design divergence — implementation migration plan"
section that explicitly catalogs the divergences and prescribes the
migration. The scaffolds are shape placeholders; implementation workers
should land the ratified interface, not preserve stale signatures.

NOT addressing as a separate finding — eager-bat-439 archive refused
because PR #3436 is still open. Worker delivered cleanly (2 approvals, CI
green, conflict markers resolved); operator manual squash-merge is the
gate.

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

* WIP: V4 work

* WIP: V4 work

* design: ratify P3 lens contract — side-channel over InferredTree

Resolves the codex BLOCKING finding on PR #3437 line 33:
- P3 was flagged as contradicting THESIS lines 105 + 342 ("compiler
  validates dimensions / by construction, not by opt-in"). Original
  framing made lens enforcement entirely external; too strong.
- Resolution: lenses are orthogonal to the homomorphism (they observe;
  they don't participate). Six commitments now ratified:
  1. InferredTree is the lens consumption point (stable contract).
  2. Lenses are folds over InferredTree (shared fold_node primitive).
  3. Lens outputs are side-channel (not feeding translate/eval).
  4. Built-in and user-defined lenses share one algebra contract;
     compiler core does not name any specific lens.
  5. Multi-lens execution is dependency-managed (no re-walks).
  6. "By construction" guarantee preserved by project-mandatory wrapper.
- B-style (lenses inside compile) vs C-style (lenses in a wrapper) is
  not architecturally load-bearing under 1-6; refactoring B<->C is
  mechanical.

Side effects:
- Open Q0 (lens architecture) marked Ratified.
- Open Q2 (InferredTree dimensional facts) marked Ratified — tree
  carries grounding only; dimensions are lens side-channel.
- New Open Q6 — multi-lens dependency-management substrate primitive
  (the substrate work commitment 5 implies).
- Note in End-to-end I/O section updated (no longer "under
  reconsideration").

The 04_infer.dag import of v4.lens.cost.SymbolicCost remains a
violation of commitment 4 and is fix-needed regardless of surface.

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

* design: integrate reviewer feedback — P5 + P6 + ratify Q1/Q3/Q4/Q5 + Q7-Q14

Major amendment integrating the second-round review on PR #3437 and the
operator's dependency-management question. Doc grows from ~440 to ~640 lines.

New ratified premises:
- P5 — Fold discipline does not imply purely local bottom-up computation.
  Stage algebras may be higher-order, effectful, constraint-bearing, or
  fixpoint-seeking. Non-local mechanisms (resolve's inherited scope, ground's
  constraint solving, coercion fold) are substrate machinery, not ad-hoc
  compiler logic.
- P6 — Dependencies are first-class typed edges. The compiler maintains a
  typed dependency graph (BindsTo / TypeDependsOn / DataDependsOn /
  EffectDependsOn / ResourceDependsOn / ModuleDependsOn / BarrierBefore /
  PlacementDependsOn) alongside the containment tree. Parallelism,
  MapReduce-style sharding, CUDA placement, memoization, and incremental
  rebuild are derived from this graph + algebra-inhabitance witnesses, not
  special compiler modes.

Substrate primitive set updated to six (added typed dependency graph +
topological/SCC machinery; probably lands in std/dependency.dag — T-21's
affected_set.dag is the incremental-rebuild specialization).

InferredTree carrier now explicitly includes the semantic dependency graph
alongside containment / binding / typeshape / inhabitance witness. Doc notes
the future-rename consideration to InferredGraph but keeps the historical
name for now.

ModelCore factored as the shared substrate of LanguageModel + HostModel
(per ratified Q1a). HostModel is a distinct peer of LanguageModel, not a
VoidGrammar variant.

LanguageModel expanded per ratified Q5 to include binding/scope rules,
effect/partiality declarations, version/dialect metadata.

Carrier taxonomy clarified: SurfaceNode / CoreNode / ResolvedCoreNode /
InferredCoreNode / TargetSurfaceNode / TargetSource. Compiler core operates
over CoreNode and its enrichments; source/target Node shapes are boundary-only.

Ratifications:
- Q1 → Q1a + factored ModelCore.
- Q3 → Q3a (parse + normalize separate logically; inspectability).
- Q4 → Q4a with required substrate laws + accumulate-vs-short-circuit policy
  via Q11.
- Q5 → Q5a with expanded LanguageModel.

New open questions:
- Q7 — LanguageModel declarative-only vs executable predicates? (Hidden
  emitter prevention.)
- Q8 — Coercion-fold completeness vs fail-closed-incomplete. Diagnostics
  must distinguish.
- Q9 — Independent witness checking (search untrusted; checker trusted).
- Q10 — Partiality and effects on ModelCore — substrate representation.
- Q11 — Outcome<T> accumulate vs short-circuit per-stage policy.
- Q12 — Bidirectional grammar law (parse-after-print target stability is
  the default; source-text-faithful round-tripping is opt-in for code-mod
  tools).
- Q13 — Language versions / dialects on LanguageModel.
- Q14 — Target selection policy under multiple valid homomorphisms.

Doc cleanups:
- "Two parameters" → "Three arguments" (input_text is also an argument).
- "project" boundary-action removed (rescinded lens-as-compile-mode artifact).
- "Nothing re-walks" rewording: each stage performs at most one disciplined
  fold/traverse and monotonically extends; facts are monotonic; no stage
  re-derives facts from raw text or duplicated source-of-truth.

Glossary expanded: ModelCore, DependencyEdge / DependencyKind, synthesized
attribute, inherited attribute, SCC condensation.

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

* WIP: V4 work

* design: address 3 BLOCKING reviews — Q1 prose / Q8 framing / Q9 + P5 search leakage

Reviewer (codex) flagged three remaining stale spots after the previous
amendment commit dc4c41b:

1. Line 97 (End-to-end I/O prose): still described HostModel as
   "LanguageModel minus the grammar" + "Open Q1" even though Q1 had been
   ratified as ModelCore + distinct HostModel. Rewrote line 97 to align
   with the ratified shape.

2. Open Q8 (coercion-fold completeness): admitted an "incomplete bounded
   search" mode (Q8b) that contradicts T-9's decidable-by-construction
   ratification. The fold is mechanical over a closed candidate set; there
   is no "search may have missed something" mode. Reframed Q8 from a
   completeness question to a diagnostic-shape question (what provenance /
   near-miss / reason-differentiation belongs in the fail-closed diagnostic).

3. P5 + Open Q9: legacy "search" framing leaked back in:
   - P5 said "performs structural-equality search against the target
     language model's declared inhabitants. The search is bounded..." —
     reworded to "enumerates the target language model's declared
     candidates and performs a structural-equality zip-fold ... deterministic
     candidate enumeration, not a heuristic search."
   - Q9 said "without re-running the search" / "search is untrusted; checker
     is trusted" — reworded around "the coercion fold's candidate
     enumeration" / "the derivation is untrusted; the witness check is
     trusted." Added Q9b for the legitimate-ambiguity question (multiple
     candidates passing structure preservation), which is a target-policy
     question (links to Q14), not a search-completeness question.

The historical "search" mentions in TL;DR / primitive set table / glossary
("supersedes search", "never a search", "(not search)") are correct
historical references and preserved.

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

* WIP: V4 work

* design: integrate reviewer's ratification-edits — P7 LawfulRewriteWitness + sharpened boundaries

Operator-direct review of the dc4c41b+524c2ad6c iteration. Landing all
amendments in one commit.

NEW PREMISE:
- P7 (ratified) — Structure-changing target lowerings (sequential→parallel
  map, left-fold→tree-reduce, CPU loop→CUDA kernel, sequential reduce→
  MapReduce) require a LawfulRewriteWitness primitive. The witness is
  declared by the target/runtime model with precondition algebra laws; the
  rewritten plan grounding is then checked by the coercion fold's EXACT
  zip-fold. Keeps "coercion fold is not heuristic search" intact while
  making room for structure-changing lowerings. Without this distinction
  implementation workers would face a false fork between cementing CUDA/
  MapReduce into the compiler (Practice 10 row 3 failure) or extending the
  coercion fold to do search (T-9 D2 violation).

NEW SUBSTRATE PRIMITIVES (table now lists 8 total — was 6):
- solve_constraints — declared constraint-solving primitive consumed by
  ground/infer. Produces a UNIQUE canonical source grounding (or ambiguity
  diagnostic). Distinct from the coercion fold. P5 wording fixed — solver
  is no longer called "the coercion fold."
- LawfulRewriteWitness — per P7, witness primitive for structure-changing
  lowerings.

P6 EXTENSIONS:
- Edge orientation convention: A → B means "A is required before B."
  Applies uniformly across all DependencyKinds.
- Conservative-by-default rule: absence of an edge is evidence of
  independence ONLY under a ClosedWorldDependencyWitness. Unknown effect/
  resource facts conservatively introduce ordering or fail-closed.
  Prevents unsound parallelism inference.
- Source-core vs TargetPlan tiers: PlacementDependsOn is TargetPlan-tier,
  introduced during translate/lowering — NOT source semantics. Source-core
  kinds: Contains, BindsTo, TypeDependsOn, DataDependsOn, EffectDependsOn,
  ResourceDependsOn, ModuleDependsOn. TargetPlan kinds: PlacementConstraint,
  TransferDependsOn, BarrierBefore (synthetic sync), shard/partition/
  device-binding.

P3 SHARPENING:
- Commitment 5 reworded: "Lenses with no interdependencies are coalesced
  into a shared traversal. Lenses with dependencies are scheduled by a
  lens-dependency DAG." Replaces the too-strong "no re-walks" wording
  while preserving Practice 3 discipline.
- Commitment 6 reworded to sharpen the lens-doesn't-feed-homomorphism vs
  wrapper-may-gate-emit/eval distinction.

GRAMMAR-AS-BIDIR-DATA DEFAULT LAW: now in the primitive description —
parse_target(serialize_target(node)) == node. Serialization is
canonicalizing; full source-text round-tripping is opt-in (Q12c), not the
default. Prevents over-commitment to impossible full bidirectionality.

CANONICAL-GROUNDING INVARIANT on ground: ground must produce EXACTLY ONE
canonical grounding per Node (with witness) OR an ambiguity diagnostic.
Translate never receives ambiguous source grounding. Prevents target
selection from leaking backward into inference.

STALE-CONTRADICTION CLEANUPS:
- P2 "Open question on HostModel shape" → "Ratified per Q1."
- "What's NOT in scope" lens line → "Lens framework implementation —
  out of initial compiler-core scope. Contract ratified by P3 + Q0;
  multi-lens substrate remains Open Q6."
- Q2 wording: "carries only grounding facts" → "carries compiler-core
  semantic facts only: locus, binding, typeshape, inhabitance witness,
  AND the P6 semantic dependency graph." Reconciles the apparent
  contradiction with P6.

Glossary expanded: solve_constraints, LawfulRewriteWitness, ConstraintGraph,
ClosedWorldDependencyWitness, canonical (source) grounding.

Doc grew to 667 lines.

The strongest form of the thesis now: the compiler transforms a canonical
grounded program graph, not just a syntax tree. Containment enables folds;
typed dependencies enable scheduling/incrementality/parallelism; canonical
grounding enables decidable coercion; lawful rewrite witnesses enable
CUDA/MapReduce-style structure changes; lenses observe the grounded graph
but do not participate in the homomorphism.

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

* design: separate ingest layer from compile-core (data-first surface)

Operator-direct ratification: compile-core operates on data (CoreNode),
not text. Text is one of several legitimate ingest entry points, not THE
entry point. Substrate is data-first.

Motivation: lens/query/affected-set/IDE workflows operate on Node data,
not text. Forcing every entry through text would either require lossless
code-mod tooling for all cases or constrain the substrate's expressiveness.
The cleanest separation is to make ingest a separable layer with multiple
entry paths, all producing CoreNode.

Signature change:

  compile(source: CoreNode, input_lang, mode) -> Outcome<Output>
  ingest_text(text, input_lang) -> Outcome<CoreNode>

Other ingest paths (no text involved):
- Programmatic builder (IDE plugins, code generators).
- Query-driven rewrite (affected_set + transformation).
- Round-trip from a prior TargetNodeTree.

All produce CoreNode; compile takes it from there.

Pipeline diagram updated to show the INGEST / COMPILE-CORE separation.
Stage table now has a "Layer" column distinguishing INGEST stages
(parse, normalize) from COMPILE-CORE stages (resolve, ground, translate,
serialize, eval).

Carrier shape progression diagram updated to show the multi-source funnel
into CoreNode.

Boundary actions:
- Compile-core: write output text (or execute), report diagnostics. Pure
  data-in / data-out otherwise.
- Ingest layer (separable): read input text only when ingesting from text.

The CoreNode is the substrate-canonical Node — six connectives + five
behaviors only, sugar dissolved. The compile contract is uniform regardless
of how CoreNode was authored.

Glossary expanded: ingest, ingest_text.

This sharpens what was already implicit (the carrier taxonomy already
distinguished SurfaceNode/CoreNode) and makes the lens/query story cleaner:
those operate on Node data directly, without going through text.

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

* WIP: V4 work

* design: integrate read/edit pipeline + self-modification (per sunny-wolf-435 review)

Major doc amendment integrating the substantive review from PR #3437's
sister doc (sunny-wolf-435 PM, against docs/design-read-edit-pipeline.md
which merged in PR #3364 on 2026-05-19).

Reviewer feedback was that the compiler-architecture doc had a substantial
gap: it covered the COMPILE direction (text/data → target) thoroughly but
was silent on the EDIT direction (CoreNode + Diff → CoreNode'), the
read/edit pipeline merged in PR #3364, and the closely-related question
"how will the compiler edit itself / regenerate stage0?"

CHANGES:

1. NEW "Load-bearing references" section (after "What this document is"):
   Comprehensive list of foundational + adjacent ratified design docs the
   compiler architecture composes with. Includes THESIS / MODELING /
   modeling-discipline / INVARIANTS / TASKS as foundational, and 11
   adjacent design docs (read-edit-pipeline, emit-stage-l25, infer-stage-l25,
   lens-application-surface, lens-framework, affected-set-lens,
   dissolution-lens, v4-close-interrogation, v4-dag-rationale,
   pure-bootstrap-zero, substrate-lambda-calculus-grounding,
   bootstrap-fact-model) plus 6 lens-specific design docs.

2. NEW 9th substrate primitive: apply_diff
   - Path / Edit / Diff vocabulary ratified in PR #3162 (std/node.dag)
   - apply_diff scaffold in lens/application.dag (T-23)
   - The substrate is read/write-symmetric: reads via fold_node /
     apply_lens; writes via apply_diff
   - Primitive set is now 9 things (was 8); TL;DR + tally line updated

3. NEW "The EDIT direction — symmetric to compile" section:
   - Read/edit primitives table (Path, Edit, Diff, apply_diff, subterm_at,
     apply_lens, affected_set)
   - The seven-step read→edit pipeline from PR #3364 § 4
   - Candidate-state pattern: gates run against apply_diff(dag, Diff),
     NOT the pre-edit graph. Same monotonic-facts invariant as P3's
     facts-flow-forward, applied to mutation.
   - EDIT direction = the "Query-driven rewrite" ingest path (cross-link
     to the ingest paths table)
   - Library-first agent surface (per read/edit doc § 6.10) — extended
     to apply to compile() too
   - Lens as (find, transform) convolution view; cross-ref to mechanical
     refactor hero case (f) in read/edit doc § 6.7b

4. NEW "Self-modification, stage0, self-edit" section addressing the
   reviewer's specific question:
   - Compiler reads its own source as CoreNode (same lens surface as
     user code; no special introspection)
   - Compiler writes to its own source via apply_diff (two paths:
     hand-authored Diff or mechanical-refactor lens)
   - stage0 regeneration is compile(self, dag, TranslateTo(rust)) — no
     special mode; the homomorphism mechanic applies identically
   - Candidate-state for self-modification safety — lenses gate the
     candidate; compiler cannot break itself silently
   - Implications: no new substrate needed; self-hosting is one specific
     compile invocation; hand-Rust-to-zero IS the loop closing.

5. Glossary expanded with Path / Edit / Diff / apply_diff / apply_lens /
   SectionRef / scope_in / candidate-state pattern / affected_set /
   self-edit-stage0 vocabulary.

The compile + edit directions are now both represented in the doc.
The two designs (this one + read/edit pipeline) compose cleanly — same
CoreNode, fold_node, Diagnostic substrate; the read/edit doc owns the
agent-surface mechanics, this doc owns the homomorphism architecture,
both are the same nine substrate primitives at different angles.

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

* design: address 3 BLOCKING codex findings on commit 77fe746

Findings on PR #3437 from codex 2026-05-20T05:24:15Z, all addressed in this
commit:

FINDING 1 — Validate-then-compile gate not type-enforced.
P3 commitment 6 said the project-mandatory wrapper preserves the "by
construction" guarantee, but that was convention, not type-level enforcement.
Updated to require Validated<Output>-style carrier discharged only by the
wrapper; bare compile() now explicitly marked as internal/non-terminal
(accessible to advanced consumers — lens framework, build tooling, self-edit
— but NOT the everyday user surface). The wrapper-as-terminal pattern is
invariant at the type level.

FINDING 2 — Substrate inventory verifiability.
The reviewer flagged "live-substrate inventory was not verified against the
v4 tree." Verified refinement.dag IS on main (1143 bytes, status "T-25-core
modeled" — landed via #3354); the doc claim was correct. Added a
"Verifiability note" pointing at the verification commands (ls + head -10)
+ added commit refs (#3354 for refinement.dag, #3162 for Path/Edit/Diff
vocabulary, #3436 for in-flight T-8 PR) so future reviews can verify
independently. Also added lens/application.dag and lens/affected_set.dag
to the inventory (they were missing).

FINDING 3 — Scaffold-vs-design divergence.
The reviewer correctly identified that the compiler scaffolds in
src/v4/compiler/ predate this doc's ratifications and have divergent
signatures (00_compile.dag's `compile(Source, TargetModel) -> TargetSource`
vs this doc's `compile(CoreNode, LanguageModel, CompileMode) -> Outcome<Output>`,
04_infer.dag's `v4.lens.cost` import vs P3's no-named-lens rule, etc.).
Added a "Scaffold-vs-design divergence — implementation migration plan"
section that explicitly catalogs the divergences and prescribes the
migration. The scaffolds are shape placeholders; implementation workers
should land the ratified interface, not preserve stale signatures.

NOT addressing as a separate finding — eager-bat-439 archive refused
because PR #3436 is still open. Worker delivered cleanly (2 approvals, CI
green, conflict markers resolved); operator manual squash-merge is the
gate.

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

* WIP: V4 work

* design: P8 compiler-self-application + refined testgen lens-family + regeneration substrate

Integrates the operator's review per 2026-05-20 — two ratifications + named
regeneration substrate.

NEW PREMISE P8 — The compiler is not exempt from its own discipline:
The compiler is itself a modeled system. Its layers (stages, language models,
lenses, testgen, target models, diagnostics, glue derivation) are modeled
as dependency graphs over the same substrate primitives. When an upstream
model changes, the compiler computes the affected downstream subgraph
(T-21 affected_set) and regenerates derivable artifacts; non-derivable
consequences fail-closed.

"No hidden anything" generalized: no implicit conventions, no manual
synchronization, no hidden emitter / parser / test-generator / integration-
updater / layer-specific-patcher / ad-hoc-Node-traversal-outside-primitives.
Every compiler-internal artifact must be a substrate primitive OR a declared
algebra OR a lens OR a projection OR a target/runtime policy.

The slogan: the compiler is the first consumer of its own modeling discipline.
If implementation workers find themselves writing ad hoc code to keep
compiler layers in sync, that is a STOP condition.

Two worked examples added under P8:
- testgen self-regeneration: Refinement<T> shape changes → affected_set
  computes which TestClaims/TestCases/target test files regenerate → lens
  family re-fires automatically on the affected subgraph.
- LanguageModel self-regeneration: LanguageModel gains a new field (e.g.,
  effect-semantics per Q10) → affected_set computes which stages/lenses
  depend on it → each extends or fails-closed on the new field.

NEW "Named regeneration substrate" section (under P8) cataloging the
substrate concepts P0 + P8 need that are not yet declared:
- ChangeSet (std/change.dag)
- AffectedSet (T-21 is the lens-frontier specialization; full version not
  yet declared)
- Projection (std/projection.dag)
- Artifact (std/artifact.dag)
- RecomputePlan

REFINED TESTGEN LENS FAMILY (per reviewer's three-layer taxonomy):
- Layer 1: TestClaimLens — InferredTree → TestClaim Witnesses (abstract
  behavioral claims: roundtrip / refinement-boundary / algebra-law /
  protocol-compat / effect-idempotency)
- Layer 2: TestCaseLens — TestClaim Witnesses → TestCase Witnesses
  (concrete cases: examples, boundary cases, property-test generators,
  fuzz seeds, regression fixtures)
- Layer 3: TargetTestProjection — TestCase Witnesses + target LanguageModel
  → target test source (Rust #[test], pytest, Jest, integration harness)

Profile invocations expanded with reviewer's full taxonomy: smoke,
boundary, property, algebra_law, effect, integration, roundtrip,
equivalence, fuzz, regression. All share std/verification.dag (landed) +
std/refinement.dag (landed) + std/dependency.dag (P6 substrate, not yet
declared) + std/testgen.dag (renamed from lens/testgen.dag, follow-up
bookkeeping).

Self-regeneration cross-reference: when a model fact changes, affected_set
computes which testgen lenses re-fire on which subgraph — no manual sync.

GLOSSARY EXPANDED: TestClaimLens, TestCaseLens, TargetTestProjection,
ChangeSet, AffectedSet, Projection, Artifact, RecomputePlan.

The compiler architecture now has the full mental model:
- Semantic substrate: 6 connectives + 5 behaviors
- Compiler substrate: 9 primitives (fold_node, traverse, grammar-as-data,
  solve_constraints, coercion fold, LawfulRewriteWitness, dep graph,
  apply_diff, diagnostic+locus)
- System substrate (not yet declared): ChangeSet, AffectedSet, Projection,
  Artifact, RecomputePlan
- Derived outputs: target code, eval values, tests, dim facts, glue,
  diagnostics, and compiler artifacts themselves (P8)

The big idea: v4 does not merely compile .dag programs. v4 models systems —
including itself — as dependency graphs, then regenerates all downstream
projections when upstream facts change.

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

* design: P9 stratified bootstrap — stage0 as generated artifact, not self-modifying code

Integrates the reviewer's critical clarification (2026-05-20): "compiler edits
itself" is loose; the precise framing is "compiler models itself; generates
candidates; promotion is guarded." Resolves the architectural ambiguity in the
prior self-modification framing without falling into v2's manual-stage0-patch
failure mode OR free-runtime-self-modification (intractable).

NEW PREMISE P9 — Bootstrap is stratified; stage0 is a generated artifact:

The compiler may model and regenerate its own implementation, INCLUDING stage0,
but no running compiler generation mutates itself in place. The compiler can
DERIVE AND VERIFY a replacement stage0 from Stage0Spec; it cannot arbitrarily
rewrite itself at runtime.

THREE-PIPELINE FRAMING (must not collapse):
1. Semantic compile pipeline — text → InferredGraph → target/eval.
2. Artifact projection pipeline — InferredGraph → generated compiler code /
   tests / docs / schemas / glue / stage1 source.
3. Bootstrap promotion pipeline — current Stage0[k] + candidates → Stage0[k+1]
   (or rejection diagnostic), guarded by BootstrapWitness + FixedPointWitness.

The mistake is collapsing all three into "the compiler edits itself."

WHAT STAGE0 IS:
- A minimal seed runner (NOT "the whole compiler but worse").
- Consumes a stable canonical CorePackage (NOT arbitrary evolving surface syntax).
- Stage0Contract declares: load CorePackage; understand stable Node/Core schema;
  run minimal fold_node/traverse; fail-closed diagnostics; emit verified artifact.

This decoupling is the structural answer to v2's pain — surface language /
parser / normalizer / lenses can all evolve without breaking stage0 because
stage0 consumes the canonical package, not the surface.

BOOTSTRAP EPOCH LOOP:
- Stage0[k] + CorePackage[k] → Stage1[k]
- Stage1[k] + SourceModels[k] → Stage1'[k]
- verify(Stage1[k] == Stage1'[k]) → FixedPointWitness[k]
- Upgrade k → k+1: ChangeSet + AffectedSet + RecomputePlan → Stage0Candidate +
  Stage1Candidate → verify → promote.

Only the promotion protocol replaces the active stage0. No back edge anywhere
else.

THREE CASES for compiler-contract changes:
1. Normal downstream (no stage0 impact) — affected artifacts recomputed.
2. Bootstrap-compatible stage0 change — current compiler generates
   Stage0Candidate; verify; promote. No manual edit.
3. Bootstrap-breaking change — requires modeled Bridge[k → k+1] migration
   package, or fails closed with BootstrapBreak diagnostic.

CRITICAL INVARIANT: "At no point does an artifact become source of truth
merely because it is needed for bootstrapping." Generated stage0.rs /
compiler.corepkg / generated compiler source / generated tests are NOT
authorities — they're disposable artifacts with witnesses. The source of
truth remains .dag models + Stage0Contract + CorePackageSchema + Projection
definitions.

CONCEPTUAL STACK (Layer 0-4):
- Layer 0: Seed (stage0 executable, minimal, audited, consumes CorePackage)
- Layer 1: Substrate models (.dag, source of truth)
- Layer 2: Compiler models (.dag, source of truth)
- Layer 3: Generated compiler artifacts (disposable, regeneratable)
- Layer 4: Verification / promotion (procedural and conservative gatekeeper)

Only Layer 0 is hand-seeded. Layers 1-2 are source of truth. Layer 3 is
disposable. Layer 4 is the gatekeeper.

TWO DISTINCT DEPENDENCY GRAPHS (must be separated):
- Program dependency graph (P6) — Contains / BindsTo / TypeDependsOn /
  DataDependsOn / EffectDependsOn / ResourceDependsOn / ModuleDependsOn /
  BarrierBefore / PlacementConstraint.
- Build / bootstrap dependency graph (new) — ModelDependsOn /
  ProjectionDependsOn / GeneratedFrom / VerifiedBy / PromotedBy /
  BootstrapDependsOn.

Keeping them separate prevents the confusion "does the compiler's own
resolver depend on the resolver it is resolving?" — answer: at epoch k,
Stage0[k] resolves model[k] enough to build Stage1[k]. No active stage
depends on its own output.

NEW BOOTSTRAP SUBSTRATE (P9 implies these; not yet declared):
- Stage0Contract, BootstrapEpoch
- CorePackage, CorePackageSchema
- Bridge (migration package for bootstrap-breaking changes)
- BootstrapWitness, FixedPointWitness
- PromotionPlan, PromotionDiagnostic / BootstrapBreak

Likely lands in std/bootstrap.dag alongside P8's regeneration substrate
(ChangeSet / AffectedSet / Projection / Artifact / RecomputePlan).

WHAT THIS RULES OUT (STOP conditions for implementation workers):
- Code letting stage0 directly edit itself at runtime.
- A "bootstrap workaround" that hand-edits stage0 outside the candidate /
  promotion path.
- A "we know this is safe" that skips fixed-point verification.
- Generated-artifact files treated as authorities.

UPDATED EXISTING SELF-MODIFICATION SECTION to cross-reference P9 and clarify
that the "compiler edits itself" framing is loose; the precise mechanic is
candidate generation + verification + promotion.

GLOSSARY EXPANDED: Stage0Contract, CorePackage / CorePackageSchema,
BootstrapEpoch, Bridge, BootstrapWitness / FixedPointWitness, promotion
protocol.

The "fractal feeling" of self-application is now resolved structurally:
the pattern is stratified (Layer 0 → Layer 4), not infinitely recursive.
Only the model layer is source of truth; the bootstrap layer is intentionally
tiny; the promotion layer is procedural; the artifact layer is disposable.

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

* WIP: V4 work

* design: address 3 new BLOCKING codex findings on P8/P9 work

Findings on commit b1cfdb8 (codex 2026-05-20T06:44:32Z):

FINDING A (3271748181) — P2 boundary discipline: T-21 affected_set as
specialization vs full AffectedSet undeclared = split regeneration authority.

Fix: clarified in "Named regeneration substrate" section that these substrate
concepts must land as a UNIFIED coherent declaration (std/regeneration.dag or
tightly-related cluster), not piecemeal. T-21's affected_set must be MIGRATED
into the unified AffectedSet — not left as a parallel concept (which would
itself be a P2 violation). Implementation order updated: declare the
regeneration substrate as a unit; migrate T-21 into the unified shape.

FINDING B (3271748191) — P3 fail-closed: "fail-closed-or-default" wording in
the language-model self-regeneration worked example allowed silent default
acceptance of missing newly-required facts.

Fix: removed "fail-closed-or-default". Replaced with explicit choice — either
(a) a typed Default<T> witness declared as substrate data (modeled default,
NOT implicit silent default), or (b) a fail-closed diagnostic. No silent
default acceptance — per P3, missing newly-required facts produce typed
witness OR diagnostic, never unsignalled default.

FINDING C (3271748200) — P2 boundary discipline: stage0 self-compile path
appeared to fold parse + normalize back into compile(...), contradicting the
text/data separation where compile-core consumes CoreNode.

Fix: rewrote the stage0-regeneration code block to show explicit
ingest_text + compile composition. Compile-core takes CoreNode (data), never
text. ingest_text is the separable boundary; compile is the pure data-in /
data-out core. Added "Equivalent paths" note showing other ways to obtain
CoreNode (already-cached, programmatic builder, query-driven rewrite) — all
funnel through compile() taking CoreNode.

The "no special regenerate stage0 mode" claim is preserved (stage0
regeneration is still compile(self_corenode, dag, TranslateTo(rust))) but the
ingest boundary is now explicit and separable. v2's manual-patch failure
mode is structurally precluded by the ratified text/data separation.

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

* design: tighten I/O — no boundary actions; everything is modeled effects

Operator-direct refinement: the "shim/modeling thing extends to reads/writes
as well." The architecturally pure approach models files, file_system, shell,
and OS independently in extdeps/; all I/O is modeled effects against modeled
resources; compile-core has no boundary actions.

CHANGES:

1. TL;DR boundary actions reframed:
   FROM: "Compile-core boundary actions: write output text (or execute),
   report diagnostics. Two actions; compile-core is otherwise pure data-in /
   data-out. Ingest-layer boundary actions (separable): read input text only
   when ingesting from a text source."
   TO: "Compile-core has no boundary actions. The compile core is purely
   data-in / data-out. All real-world I/O — reading source from disk,
   writing target source to disk, executing on a host, reporting diagnostics
   to stderr — is modeled as effects against modeled resources
   (extdeps/file_system.dag for files, extdeps/process.dag for shell/OS,
   extdeps/network.dag for network), composed by peripheral shims outside
   the compile-core surface."

2. End-to-end I/O section rewritten:
   - Removed ingest_text from the public substrate primitive signature.
   - Added explicit "Peripheral shims for text and file I/O" subsection
     showing the composition: file_read (modeled effect) + ingest_text (shim)
     + compile (pure) + file_write (modeled effect) — each step is its own
     substrate-modeled operation, NOT a compile-core boundary action.
   - Added "Why this matters architecturally" — no hidden side effects;
     dry-run works as composition; incremental rebuild works because every
     artifact's provenance is modeled; self-modification is safe because
     apply_diff is modeled, not implicit.
   - Slogan: "No implicit I/O. Files are not the architecture. Effects are
     modeled, not assumed."

3. Glossary added:
   - peripheral shim — user-facing convenience composing modeled effects
     with compile-core; NOT a substrate primitive.
   - modeled effect — real-world I/O declared as substrate data in extdeps/
     carrying EffectDependsOn / ResourceDependsOn edges; visible to lenses;
     substitutable for dry-run.

This sharpens P0 + P8 + P3-dry-run: there are no implicit side effects
anywhere in the architecture. Files are orthogonal to the architecture;
they're modeled in extdeps/file_system.dag, NOT load-bearing for compile.

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

* design: tighten catamorphism/homomorphism/coercion terminology + MVP routes

Four targeted tightenings before this wave of worker dispatch:

1. NEW "Terminology" subsection before P5: catamorphism / homomorphism /
   coercion are three terms at three levels (mechanism / noun / verb).
   The coercion fold is a catamorphism whose job is to verify a homomorphism.
   Translation IS the homomorphism (the noun); coercion is the
   verification verb. Doc passages conflating "coercion fold" with
   "homomorphism mechanic" generically are sloppy and should be flagged.

2. Coercion fold primitive description now names the TranslatePlan
   extension slot: conceptually
     TranslatePlan = ExactCoercion(source_grounding, target_node)
                   | RewrittenThenCoerced(rewrite_witness, ...)
   MVP implements only ExactCoercion; future LawfulRewriteWitness (P7)
   lands the second variant without refactor.

3. Artifact carrier (in the regeneration substrate) now reserves
   bootstrap-related ArtifactKind variants up front: Stage0Candidate,
   CorePackage, WitnessBundle. Lets P9 bootstrap substrate land later
   without forcing artifact/projection refactor.

4. NEW "MVP routes — named explicitly" section before "What's NOT in scope":
   - Core MVP: compile-core homomorphism produces TargetSource from CoreNode
   - MVP-A (translate-only): Core MVP + file_system shim → file-to-file
   - MVP-B (eval-only): Core MVP + host_model + T-22 → Value
   Either MVP-A or MVP-B is sufficient as the first proof point;
   both together is the strongest exercise.

The terminology section is the key piece — operator + reviewer were
unclear on whether we were moving from coercion to homomorphism; the
answer is they coexist at different levels and the doc should use them
precisely. The other three are scope-reservation moves that prevent
future refactor when held substrate (LawfulRewrite, bootstrap, multi-lens)
eventually lands.

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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