Skip to content

design-dissolution-lens: propose L1.7–L1.12 from 2026-05-18 ingest - #3313

Merged
briansrls merged 15 commits into
mainfrom
session/sunny-wolf-435
May 18, 2026
Merged

briansrls merged 15 commits into
mainfrom
session/sunny-wolf-435

Conversation

@briansrls

Copy link
Copy Markdown
Contributor

Summary

  • Adds six proposed Layer-1 lenses (L1.7–L1.12) to docs/design-dissolution-lens.md, derived from the 2026-05-18 review ingest against main@e7b8a8d. Each is corroborated as still present in the worktree.
  • Each section follows the existing L1.x format and includes a concrete code-level match case + clean-shape example so the structural signature is reviewable without chasing repo paths.
  • §8 slipped-by ledger gains rows pinned to current main file locations (per §3 derivation methodology: slipped-by → invariant → substrate root cause → lens).

The six proposed lenses

Lens Kills Anchor finding
L1.7 Off-substrate-fact prose-asserted facts (algebra inhabitance / width / opacity claimed in a comment, not enforced by structure) F3 (fermi_meet w/ no Lattice data witness), F4 (Word64 { bytes: List<Byte> }), F11 (ResourceHandle opacity in prose)
L1.8 Wrong-home orphan operations whose argument types all live in an upstream file (M9 mechanized) F5 (nat_compare in float.dag)
L1.9 Vacuous-arm exhaustive-but-empty match arms in discipline functions (_well_formed / _valid) F1 (ComputationNode { behavior: _ } => true)
L1.10 String-escape-hatch : String fields whose name matches a canonical typed model in scope; generalizes L1.6 F6 (ShellCommand { command: String } vs typed process.Command)
L1.11 Plausible-fallback None => Ctor arms where Ctor is a sibling variant of the function's return type (not Outcome<_>) F10 (derive_effect_shape DELETE None => CreateEffect)
L1.12 Parallel-authority duplicate concept homes with no // Authority: canonical / historical marker; degenerate case = planned-but-absent import target F9 (Bool/Char/Url in both dsl/std and src/v4/std), D2-resolver gap

Larger patterns

The six proposals collapse the 14-item review ingest (12 exploratory + 2 reflective) into a smaller set of structural patterns:

  • Pattern A — "fact lives in prose, not in type" → L1.7 (F3, F4, F11)
  • Pattern B — "operation in wrong home" → L1.8 (F5; partially F1, D2-resolver)
  • Pattern C — "exhaustive in shape, vacuous in content" → L1.9 (F1)
  • Pattern D — "String escape hatch where typed model exists" → L1.10 (F6); L1.6 already covers F8's template subcase
  • Pattern E — "fabricated sibling instead of typed diagnostic" → L1.11 (F10)
  • Pattern F — "parallel authority" → L1.12 (F9, D2-resolver)

Findings already covered by existing lenses (no new design needed): F2 (L1.4 carrier-clone), F7 (L1.5 catamorphism, also tracked LB-P10-3213), F8 (L1.6 emit/template), F12 (T-31 de-prose lane).

Scope

  • Design proposal only — Status: proposed in each new section header.
  • Touches docs/design-dissolution-lens.md only. No substrate / load-bearing file changes; no Track-2 substrate primitives are being committed to (L1.8 in particular notes that its full mechanization likely needs a concept-DAG parent edge primitive that doesn't exist yet).
  • Per §9, no interim hand-script enforcement is being proposed — lenses are compiler-integral, gated on CP-1 parse capability.

Open design questions for review

  1. L1.8 ordering — is the imports edge a sufficient proxy for "upstream concept" or does this need a richer concept-DAG primitive first?
  2. L1.10 canonical-name table — does this live in the lens definition, or should it be derived from a per-file // Canonical: <field-name> marker on the typed models themselves (so adding a new canonical type doesn't require touching the lens)?
  3. L1.11 escape valve — or_default(opt, default) style helpers are a real shape; is the // Anchor: total-by-design marker the right opt-out, or should the lens look for the second-argument-as-default signature itself?
  4. L1.12 authority markers — // Authority: canonical / historical is a new header convention; should this be added to modeling-discipline.md Practice 9 in the same PR or a follow-up?

Test plan

  • Review each L1.x section for signature precision (no false-positive shape on clean substrate)
  • Confirm slipped-by ledger entries match current main file locations (corroboration done in PM session 2026-05-18 against e7b8a8d)
  • Decide which of the four open design questions block landing this as Status: proposed vs. Status: accepted
  • Identify which (if any) of L1.7–L1.12 should be promoted from proposed to accepted in this PR vs. follow-up

🤖 Generated with Claude Code

briansrls and others added 2 commits May 18, 2026 18:13
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>
…y 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>

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

BLOCKING (3)

Root Cause

  • docs/design-dissolution-lens.md The L1.7 width lens stops at the outer carrier instead of modeling the full Word-to-Byte-to-Bit refinement chain → add the Byte and FloatBody refinements or require a recursive width proof.
  • docs/design-dissolution-lens.md Wrong-home detection lacks a structural primary-concept selector for functions → derive home from the full signature and declared witness target, not just from argument files.
  • docs/design-dissolution-lens.md The duplicate-home lens has no structural carrier for authority/disposition → require a .dag declaration, alias/import to the canonical type, or deletion/migration instead of comment markers.

⚠️ The proposed lens set needs these hard-gate semantics tightened before it becomes a reliable design reference.

Comment thread docs/design-dissolution-lens.md Outdated

**Clean shape (the cure):**
```dag
type Word64 { bytes: List<Byte> where len(_) == 8 }

This comment was marked as resolved.

Comment thread docs/design-dissolution-lens.md Outdated
> `src/v4/std/algebra.dag`). Mechanizes MODELING M9 (DFS the concept
> DAG).

- *Signature:* a `fn f(x: T, ...) -> ...` where every argument's type is

This comment was marked as resolved.

Comment thread docs/design-dissolution-lens.md Outdated
- *Decidable:* yes — name uniqueness across the corpus + header marker
check + import-target existence check.
- *Verdict:* hard error.
- *Escape:* one file carries `// Authority: canonical`, the other

This comment was marked as resolved.

briansrls and others added 2 commits May 18, 2026 14:26
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>
@briansrls

Copy link
Copy Markdown
Contributor Author

Addressed in cfbc247c0 (which incorporated the L1.7 recursive-width fix from operator's 87df24bff WIP). The comment was anchored at b9eabaae line 243, which had the single-line clean shape type Word64 { bytes: List<Byte> where len(_) == 8 } — that left Byte unconstrained and was the exact finding here.

Current HEAD (docs/design-dissolution-lens.md:258-261):

// machine.dag — recursive refinement chain
type Bit
type Byte   { bits:  List<Bit>  where len(_) == 8 }
type Word64 { bytes: List<Byte> where len(_) == 8 }   // 8 × 8 = 64 ✓

The signature change at lines 200-211 also makes the recursive-discharge requirement explicit ("walk every field whose type is a substrate collection, require a length refinement at each level until the recursion bottoms out at a fixed-cardinality leaf or a primitive bit"), so the lens definition itself — not just the example — requires the full chain.

— sent from sunny-wolf-435

@briansrls

Copy link
Copy Markdown
Contributor Author

Addressed in cfbc247c0. The argument-types-only signature at b9eabaae line 254 (the anchor for this comment) was specifically the false-positive risk this finding flags: a constructor fn make_foo(x: X, y: X) -> Foo where Foo lives in current file Y would have been rejected even though Foo is the produced concept.

The new four-rule cascade (lines 286-307) handles the constructor/parser shape via rule (3) + rule (4):

  • Rule (3) requires both argument types AND the return type to converge in a single upstream file X. A constructor fn(X) -> Foo fails because the return type Foo is not in X.
  • Rule (4) catches the residue — "if none of (1)–(3) selects a single owning type, the function is genuinely cross-cutting and the lens does not fire."

So constructors, parsers (fn(String) -> Outcome<Foo>), and any function whose produced concept lives in the current file pass rule (4) without annotation.

The F5 nat_compare case still fires: rule (2) (same-type closure) selects Nat, and the function lives in float.dag ≠ nat.dag. The lens keeps the target finding while admitting the constructor/parser shape — exactly the M9 + zero-false-positive bar.

— sent from sunny-wolf-435

@briansrls

Copy link
Copy Markdown
Contributor Author

Addressed in cfbc247c0. The b9eabaae line 412 escape valve — // Authority: canonical / // Authority: historical { dissolves_when: <trigger> } — was the exact prose-as-authority shape this finding flags. Self-consistency hit: L1.7 in the same PR exists to kill prose-asserted facts, and L1.12 was using a prose marker as its discharge. Same shape, same violation of P2 / MODELING's no-meta-language rule.

Current L1.12 Escape clause (lines 465-480) states it explicitly:

The lens does not accept a comment marker as authority, because prose-as-authority is exactly the shape L1.7 kills. The only passing shapes are themselves structural:

  1. Alias / re-export. The non-canonical file does not redeclare type T; it imports the canonical declaration and exposes it via a type T = <canonical-module>.T alias-identity edge.
  2. Structural retirement record. A data row in a designated retirement ledger names the historical declaration and a dissolution trigger, e.g. data bool_dsl_std_retired: HistoricalDeclaration = { type: dsl.std.types.Bool, dissolves_when: <trigger> }. The lens reads the ledger as data, not as prose.
  3. Deletion / migration. The historical declaration is removed in the same change and consumers are repointed at the canonical home.
    Comment markers — including a // Authority: canonical header — do not satisfy the escape, by construction.

The signature itself (lines 461-463) also drops the comment check — "name uniqueness across the corpus and import-target existence are both queryable from the parsed model. No comment/prose inspection." Authority is now a structural fact (alias edge / ledger row / absence) read from the parsed model, not from comment text.

— sent from sunny-wolf-435

briansrls and others added 3 commits May 18, 2026 18:37
…cts 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>
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>
briansrls and others added 5 commits May 18, 2026 15:26
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>
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>
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>
briansrls added a commit that referenced this pull request May 18, 2026
§5 → fresh composite manager lanes under witty-cat-59 (no reused
managers, per operator); two non-migrated exceptions (vivid-carp-207
= sole #3280 freeze custodian; fierce-cat-31 = lens-fan-out closeout).
§7 → consolidated decision sheet: the A-vs-B root ruling explained in
tradeoff terms + every pending blocking question (#3280 disposition,
#3240 ratification, T-25-core, Wave-0 go, fresh-lane defaults, de-prose
py removal, #3313) with recommendations.

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

BLOCKING (4)

Root Cause

  • docs/design-dissolution-lens.md Primary-concept selection treats observation codomains as peer home signals instead of structural results of the receiver concept → classify canonical observation carriers such as Bool/Ordering separately and select the domain concept from arguments or witnesses.
  • docs/design-dissolution-lens.md The lens escape model lacks a structural exception carrier → replace comment anchors with .dag witness rows consumed by the lens, or make unresolved cases fail pending relocation.
  • docs/design-dissolution-lens.md The L1.8/L1.9 escape valves encode reviewer decisions outside the model → move the waiver facts into structural .dag data or remove the automatic escape.
  • docs/design-dissolution-lens.md The duplicate-home detector equates lexical spelling with concept identity → key the lens on resolved declaration identity/canonical concept namespace and only treat same-concept redeclarations as duplicates.

⚠️ The prior comments are addressed, but the new hard-gate semantics still have false-negative and prose-escape holes.


**Concrete match — F5 (`src/v4/std/float.dag:52-62`):**
```dag
// in float.dag, but every argument lives in nat.dag

This comment was marked as resolved.


> **Status: proposed.** Derived from finding F1
> (`node_locally_well_formed` discharges every `ComputationNode { behavior: _ }`
> with `=> true`). Distinct from L0.12 (non-exhaustive match): the arm is

This comment was marked as resolved.

Comment thread docs/design-dissolution-lens.md Outdated
> `extdeps/process.dag` already models a typed
> `Command { program, argv0, args, env }`). L1.6 catches string templates
> as emitters; L1.10 catches strings as *carriers* for domains that have
> a typed model in scope.

This comment was marked as resolved.


## 6. The discriminant / catamorphism distinction

L1.1 and L1.5 enforce one algebraic fact worth stating directly: a

This comment was marked as resolved.

briansrls added a commit that referenced this pull request May 18, 2026
#3313 is in active design rework (L1.6 retired→L1.10 family, A0/A1
umbrella, pre-Practice-10-ratification). §7 row 7 updated: it's no
longer flat L1.7–L1.12; Wave-2 batch (d) held track-not-finalize so
witnesses aren't authored against the moving taxonomy; batches a/b/c
and the keystone framing unaffected (#3313 reinforces #1=B/#3240).

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

Copy link
Copy Markdown
Contributor Author

Already addressed in d1ca4bd46 (which absorbed my pending edits via an operator WIP). The exact false negative — nat_compare(Nat, Nat) -> Ordering not firing because the old rule 2 only admitted T-returning or Bool-returning closures — was the motivating case for the L1.8 rewrite.

Current state (docs/design-dissolution-lens.md:518-548):

  • A new canonical_observations: Set<CanonicalObservation> substrate registry classifies observation carriers (Bool, Ordering, Unit, …) as substrate data, not a hardcoded list.
  • Rule 2 is rephrased as "Domain-typed function": strip observation codomains and check if the remaining non-observation types are all the same T. The doc explicitly walks through fn(Nat, Nat) -> Ordering selects Nat; fn(Nat) -> Nat selects Nat; fn(Nat, Nat) -> Bool selects Nat.
  • Decidability bullet now reads "canonical_observations registry membership, witness-field membership, non-observation-type uniformity, and the import graph are all structural facts in the parsed model."

So nat_compare now fires under rule 2 (primary concept = Nat) and the lens reports float.dag ≠ nat.dag as the wrong-home case it was supposed to catch. No comment anchor, no hardcoded type list — the observation set lives in substrate data, satisfying A0.

— sent from sunny-wolf-435

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

Copy link
Copy Markdown
Contributor Author

Already addressed in `d1ca4bd46`. Line 540 on `a8c18bf4` was the `// Anchor: cross-cutting { because: }` comment-anchor escape — exactly the prose-as-authority shape this finding flags, and exactly what L1.7 in the same PR exists to kill. Self-consistency hit.

Current state (`docs/design-dissolution-lens.md:554-569`):

Escape (structural — no comment anchors): (4) cross-cutting functions pass via rule (4) without an exemption. For rule (1)/(2)/(3) cases where the lens fires but the function legitimately belongs in its current file, the exemption is itself a substrate data row read by the lens:
```dag
data foo_wrong_home_exemption: WrongHomeExemption = {
function: foo_fn,
because: bridge, // closed vocabulary
// (bridge / coercion / display)
}
```
Comment anchors do not satisfy the escape, by construction. The vocabulary token set (`bridge`, `coercion`, `display`) is itself a closed coproduct declared structurally — extending it is a data edit, not a doc edit.

The lens now reads the exemption as data, not as comment. Same shape as L1.10.b's existing `CanonicalCarrier.Exemption` row and L1.12's `HistoricalDeclaration` ledger — three escape mechanisms across the lens suite, all structural, all read from substrate `data` rows.

— sent from sunny-wolf-435

@briansrls

Copy link
Copy Markdown
Contributor Author

Already addressed in `d1ca4bd46`. Same shape as the L1.8 escape finding — line 589 on `a8c18bf4` was the `// Anchor: trivially-true { because: }` comment-anchor escape, which was prose-as-authority and self-inconsistent with L1.7 in the same PR.

Current state (`docs/design-dissolution-lens.md:615-629`):

Escape (structural — no comment anchors): the exemption is itself a substrate data row read by the lens:
```dag
data unit_is_unit_vacuous_arm_exemption: VacuousArmExemption = {
function: unit_is_unit,
at_variant: Unit,
because: variant-has-no-children, // closed vocabulary
// (variant-has-no-children /
// identity-on-Unit /
// proven-unreachable)
}
```
Comment anchors do not satisfy the escape, by construction. The `because` vocabulary is itself a closed coproduct declared structurally — extending it is a data edit.

All three escape mechanisms in the lens suite (L1.8 `WrongHomeExemption`, L1.9 `VacuousArmExemption`, L1.10.b `CanonicalCarrier.Exemption`, plus L1.12's `HistoricalDeclaration` ledger) are now substrate `data` rows. No comment anchors anywhere in the suite.

— sent from sunny-wolf-435

@briansrls

Copy link
Copy Markdown
Contributor Author

Already addressed in `d1ca4bd46`. Line 787 on `a8c18bf4` was the lexical-spelling signature ("a type name `T` introduced by any `type T` declaration form in two different `.dag` files") — and the false positive on `network.Result` vs `compiler.normalize.Result` (module-scoped homonyms in unrelated namespaces) is the exact M2 / extdeps-fidelity hazard this finding flags.

Current state (`docs/design-dissolution-lens.md:824-851`):

Signature (resolved concept identity, not lexical spelling): two `type T1` and `type T2` declarations in different files are duplicates IFF they resolve to the same canonical concept identity AND neither is a structural alias of the other. The lens does not key on lexical name equality — `network.Result` and `compiler.normalize.Result` are different concepts in different namespaces and are not duplicates; what makes two declarations a duplicate is shared canonical-concept membership, declared structurally:
```dag
data bool_concept: CanonicalConcept = {
canonical_home: v4.std.logic.Bool,
members: { dsl.std.types.Bool }, // historical mirrors
}
```
The lens fires when two type declarations claim membership in the same `CanonicalConcept` row without one being a structural alias / retirement / migration of the other. Same lexical name in different concepts does not fire.

Decidable: yes — `CanonicalConcept` registry membership and structural-alias edges are queryable from the parsed model. No lexical name equality, no comment/prose inspection.

The exact case this finding raises — `Result` declared in module-scoped namespaces — no longer fires. Concept identity is established by an explicit `CanonicalConcept` row claiming co-membership; unrelated declarations with the same local name have no such row and pass naturally. Extdeps fidelity is preserved because an extdeps-modeled spec can declare its own canonical concepts without colliding with substrate-internal lexical homonyms.

— sent from sunny-wolf-435

briansrls added a commit that referenced this pull request May 18, 2026
#3313 author flagged two real Wave-2 sequencing gaps: (1) unenumerated
std/ prerequisite carriers the L1.x lenses read (canonical_observations,
CanonicalConcept, 3 Exemption registries) — T-25-core-class, no owning
T-# yet (P10-shape gap); (2) three derived lens-stages (match_arm_shape,
closed_vocab_scan, concept_home) = Compiler-Pipeline+Lens lane, NOT
Dissolution. Added §4 Wave-2-prereq block + cross-lane edge
(Compiler-Pipeline builds → Dissolution Wave-2 consumes); §5 Dissolution
row annotated. Reinforces batch-(d) hold.

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

(A) still-hawk-102 third self-correction, verified: #3241 (fold) + #3242
(🟡-legend) BOTH merged; the v4 audit sweep #3240-C1 was gated on #3242
(merged), NOT on the A1 invariant — C1 already in motion independently.
Retracted the 'authorizing A1 kicks off the v4 sweep' framing in
§3(a)/§7#3a: A1 ⇒ ONLY the small placement PR, maximally low-stakes.
(B) sunny-wolf-435 (#3313 author) classification, verified NONE fold
under T-25-core: (1a) canonical_observations/CanonicalConcept → NEW T-#
'lens-supporting concept registries'; (1b) 3 Exemption registries →
fold into each lens's own task, no T-#; (2) 3 derived lens-stages →
NEW shared T-# 'Wave-2-prereq lens-pipeline derivations'. Two new
owning-T#s to assign (P10-shape). §4 Wave-2-prereq block rewritten.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@briansrls
briansrls merged commit 54aed08 into main May 18, 2026
7 checks passed
briansrls added a commit that referenced this pull request May 18, 2026
…ty-early)

sunny-wolf-435 (#3313 author), verified vs #3313 §4/§9/§10: Layer-0
(L0.1-L0.15) reads parse+resolve only (both LANDED), NO T-9 → CI
hygiene hard-gate goes live END-WAVE-1 once lens-pipeline-derivations
+ Layer-0 lens stage land. Layer-1 (L1.1-L1.12) needs post-T-9 +
concept registries → Wave-3. §4 W1 now carries the early Layer-0
gate; W3 the L1.x fan-out; batch-d hold unchanged for L1.x. Directly
serves the operator 'maximum utility as early as possible (without
compromising standards)' directive.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@briansrls briansrls mentioned this pull request May 18, 2026
Closed
6 tasks
briansrls added a commit that referenced this pull request May 18, 2026
…(discussion) (#3322)

* docs: R4 program dispatch plan — T-1..T-32 dependency chart + lane mapping

Discussion artifact: full remaining-work dependency graph, the keystone
cluster funnelling through T-4, the Wave-0 dispatch-now set, and the
proposed lane/manager mapping to v4-done. For operator + lane-manager
review ahead of program-wide fan-out.

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

* docs: fold Lane A/B/Dissolution review corrections into R4 dispatch plan

Consolidated single-commit update from the 3/4 lane-manager reviews on
#3322: T-20 materially advanced via merged #3213; T-30 interim P5(b)
mirror already on main; T-9/CP-1b is a parallel T-9 prereq off the T-4
keystone edge; T-26 std-canonical with Lane A conduit; T-31 rider vs
mop-up split; lens-program rows confirmed. T-4-mgr rows pending explicit
ack (consistent with standing #3280 hold).

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

* WIP: May 18

* docs: fold T-4-mgr review — staleness fixes + widened keystone scope

4/4 lanes now ratified. T-4-mgr (vivid-carp-207) verified vs main:
T-29(#3267)/T-4.10(#3168)/T-4.12(#3171) already LANDED, not Wave-0 —
parallel count ≈14→≈11. New decision-relevant finding: pre-D2-reversal
landed files (spice/llvm_ir) carry a Practice-10/#3240-keystone-gated
rework obligation (same class as T-4 ×5 / #3280) — widens the keystone
blast radius. T-4 'Depends on' disambiguated (#3240 ratification, not
merged numeric #3226). T-29 residual #3277 attribution flagged open.

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

* docs: fix §5/§6 internal consistency vs folded corrections (Lane A finding)

Lane A review caught §5/§6 not updated in the prior folds: §5 still
listed T-29/T-4.10/T-4.12 as T-4-mgr Wave-0 (now LANDED), ambiguous
'std / Lane A' T-26 ownership, stale Dissolution Wave-0; §6 read as
open review asks. §5 now matches §2/§3/§4 (T-26 std-authoritative /
Lane A conduit; T-4-mgr Wave-0 empty; Dissolution T-31(b)/T-30
generated-checker); §6 → ratified status (4/4 lanes, operator §3 open).

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

* WIP: May 18

* docs: fresh-lane structure (§5) + operator decision sheet (§7)

§5 → fresh composite manager lanes under witty-cat-59 (no reused
managers, per operator); two non-migrated exceptions (vivid-carp-207
= sole #3280 freeze custodian; fierce-cat-31 = lens-fan-out closeout).
§7 → consolidated decision sheet: the A-vs-B root ruling explained in
tradeoff terms + every pending blocking question (#3280 disposition,
#3240 ratification, T-25-core, Wave-0 go, fresh-lane defaults, de-prose
py removal, #3313) with recommendations.

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

* docs: fix §1 ASCII keystone diagram vs §3 (cursor BLOCKING — T-29)

§1 graphic still drew T-29 inside the keystone box while §3/§2/§5
treat it as LANDED (#3267), not a keystone — same single-chart
internal-consistency class as the §5/§6 fix. Diagram now: 3-item
cluster (P1-KEYSTONE / T-25-core / T-30); T-29 shown LANDED below.

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

* docs: fold #3313 lens-rework impact (Wave-2 taxonomy + batch-d hold)

#3313 is in active design rework (L1.6 retired→L1.10 family, A0/A1
umbrella, pre-Practice-10-ratification). §7 row 7 updated: it's no
longer flat L1.7–L1.12; Wave-2 batch (d) held track-not-finalize so
witnesses aren't authored against the moving taxonomy; batches a/b/c
and the keystone framing unaffected (#3313 reinforces #1=B/#3240).

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

* docs: record operator B2 ruling on #3321 driver shape (§7 row 8)

Operator ruled 2026-05-18: substrate-native (B2). registry.dag splits
to its own .dag PR (lands now); the ~467-LOC tools/ Rust crate dropped
entirely, B1 also rejected — no interim out-of-substrate enforcement
shell (Python OR Rust), same thesis ruling as the de-prose-py kill.
Whole-corpus gate re-scoped to the v2 filesystem-walk substrate
primitive = the T-21/T-24 corpus-drive capability (PREFIX = first
consumer). Operator-accepted: CI lens gate lands when that lands.

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

* WIP: May 18

* docs: fold still-hawk-102 review — keystone spec sharpness + 2-owner fix

(1) #3240 is a CLOSED/SUPERSEDED tracker, NOT ratifiable — the keystone
artifact is a not-yet-drafted modeling-discipline.md fold PR that
still-hawk-102 owns drafting; §7 #3a → "authorize draft", §3 rewritten.
(2) "one decision" overstated → "2-3 distinct operator items"; A-vs-B=B
stated as IMPLIED by the keystone-fold, not equivalent. (3) §5 two-owner
lens seam fixed: Fresh Compiler-Pipeline lens scope GATED on
fierce-cat-31 fan-out closeout (one lens owner; no P2 parallel-authority
drift). (4) §7 #2 no-revert-of-862bbde6e clause added. Self-consistency
pass: fixed 2 stale "ratify #3240" stragglers (§3 blast-radius, §6 r5).

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

* docs: fold sunny-wolf-435 Wave-2 prereq + cross-lane edge (#3313 author)

#3313 author flagged two real Wave-2 sequencing gaps: (1) unenumerated
std/ prerequisite carriers the L1.x lenses read (canonical_observations,
CanonicalConcept, 3 Exemption registries) — T-25-core-class, no owning
T-# yet (P10-shape gap); (2) three derived lens-stages (match_arm_shape,
closed_vocab_scan, concept_home) = Compiler-Pipeline+Lens lane, NOT
Dissolution. Added §4 Wave-2-prereq block + cross-lane edge
(Compiler-Pipeline builds → Dissolution Wave-2 consumes); §5 Dissolution
row annotated. Reinforces batch-(d) hold.

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

* docs: re-tee keystone ask to verified-exact (still-hawk self-correction)

still-hawk-102 verify-don't-trust'd its own review #1: the keystone
FOLD is ALREADY on main (modeling-discipline.md §581-763). Both prior
framings ('ratify #3240' and 'authorize a drafting effort') were wrong.
Corrected verified-exact: operator ratifies the verbatim invariant
blockquote at modeling-discipline.md ~§594-600 (exists, flagged
proposed/#3240-A1); still-hawk then lands it into INVARIANTS.md+
MODELING.md + de-hedges 3 sites — SMALL (~30-60 ln, mechanical, low-risk),
ratify-exact-text-today not a drafting effort. Downstream effort = the
retroactive v4 audit sweep (#3240 C1). §3(a)/§7#3a/§6r5/trailer aligned.

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

* docs: fix last stale 'not-yet-drafted' straggler (§3 blast-radius)

* docs: keystone retraction (C1 not gated on A1) + Wave-2 prereq classification

(A) still-hawk-102 third self-correction, verified: #3241 (fold) + #3242
(🟡-legend) BOTH merged; the v4 audit sweep #3240-C1 was gated on #3242
(merged), NOT on the A1 invariant — C1 already in motion independently.
Retracted the 'authorizing A1 kicks off the v4 sweep' framing in
§3(a)/§7#3a: A1 ⇒ ONLY the small placement PR, maximally low-stakes.
(B) sunny-wolf-435 (#3313 author) classification, verified NONE fold
under T-25-core: (1a) canonical_observations/CanonicalConcept → NEW T-#
'lens-supporting concept registries'; (1b) 3 Exemption registries →
fold into each lens's own task, no T-#; (2) 3 derived lens-stages →
NEW shared T-# 'Wave-2-prereq lens-pipeline derivations'. Two new
owning-T#s to assign (P10-shape). §4 Wave-2-prereq block rewritten.

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

* docs: final keystone re-tee — C1 sweep #3243 DONE (verified), A1 = sole open

* docs: rename live keystone gate → 'Practice-10 A1 invariant'; #3240 = closed-tracker only (cursor editorial)

* WIP: May 18

* docs: fix T-18 forward-dep violation (BLOCKING) + wave-ordering convention

Valid BLOCKING: §2 + TASKS.md say T-18 (coverage meta-lens) depends on
T-12/T-13 ('meta over the other lenses'), which only become real in
Wave 3 — yet §4 listed T-18 in Wave 2 (consumer before input = Facts-
Flow-Forward violation). Moved T-18 Wave 2 → Wave 4 (after T-12/T-13
real). Added a wave-ordering convention note: Wave = membership not
intra-wave sequence; §2 Depends-on orders within a wave; consumer-
before-input across waves is the real violation class.

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

* docs: topological re-sort of wavefront (BLOCKING T-16 + pre-empt queued)

Operator BLOCKING review fired consumer-before-input findings (T-18,
T-16, and the same class T-4.8/T-17). Replaced the weak intra-wave
convention with a TOPOLOGICAL invariant (a task is strictly later than
every dep; within-wave = mutually independent, dispatch-safe on face)
and re-sorted: W2 drops T-4.8; W3 gains T-4.8; W4 gains T-17 (deps T-12
real W3) + T-18; W5 = T-16 (deps T-11 W4); W6 = T-15 terminal. Every
consumer now strictly after its fresh inputs.

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

* docs: mirror §4 topological re-sort into §5 (codex BLOCKING residual)

codex BLOCKING (vs ed8b3b9, pre-resort) demanded T-18-after-T12/13,
T-16-after-T-11, AND 'mirror that gating in §5'. §4 was already fixed
by 9cd9831; the residual was §5 not mirroring it — the Compiler-
Pipeline 'Gated' cell was a flat 'post-T-4' bag obscuring the wave
sequence. Now §5 Compiler-Pipeline + Test/Bootstrap-Infra gated columns
explicitly mirror §4 topology (W2 T-9 → … → W5 T-16 → W6 T-15).

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

* docs: fold L0/L1 asymmetry — Layer-0 hygiene CI gate early (max-utility-early)

sunny-wolf-435 (#3313 author), verified vs #3313 §4/§9/§10: Layer-0
(L0.1-L0.15) reads parse+resolve only (both LANDED), NO T-9 → CI
hygiene hard-gate goes live END-WAVE-1 once lens-pipeline-derivations
+ Layer-0 lens stage land. Layer-1 (L1.1-L1.12) needs post-T-9 +
concept registries → Wave-3. §4 W1 now carries the early Layer-0
gate; W3 the L1.x fan-out; batch-d hold unchanged for L1.x. Directly
serves the operator 'maximum utility as early as possible (without
compromising standards)' directive.

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

* docs: restore T-29 as TASKS.md-declared T-4-cpp keystone feeder (codex RC)

codex REQUEST_CHANGES, VERIFIED vs origin/main: TASKS.md:64/:286/:1035
still declares T-29 a hard prerequisite of T-4's cpp slice
({P1-KEYSTONE,T-30,T-29,T-25-core}→T-4), and #3277 (T-29 residual) is
OPEN — only #3267 (core) merged. The prior "T-29 LANDED / not a
keystone / removed from critical branch" reclassification was a real
P2/Practice-9 documentation-authority violation (dispatch graph
disagreeing with the source of truth → could mis-sequence T-4). T-29
restored to the keystone cluster across §1 graph, §2 row, §3 table,
§4 wave note, §5 extdeps/T-4, §6 review-status; de-classify only when
#3277 lands AND TASKS.md updates (authority = TASKS.md, not this plan).

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

* docs: §7 #3b — T-25-core is authorize-to-build (ratified Category-6 shape), not an open design fork

---------

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: 55092ea5 · Trigger: schedule
  • Thinking: 332s wall

BLOCKING (3)

Root Cause

  • docs/design-dissolution-lens.md Practice-10 ratification is asserted before the authority exists → either land the Practice 10 text in the same PR or frame A0/A1 here as proposed until that authority lands.
  • docs/design-dissolution-lens.md The detector equates having a diagnostic carrier with using it → match missing-info arms that return any success constructor, including Produced, and require Rejected on unknown.
  • docs/design-dissolution-lens.md CanonicalConcept membership is treated as both detector input and the missing authority witness → add a concept-resolution/completeness gate that fails closed when duplicate candidates lack a canonical row, or split registered duplicates from unmarked duplicates.

⚠️ The prior comments are addressed, but the revised design still has authority and false-negative holes in the proposed hard gates.


Every dissolution finding violates one invariant, in one of two
directions:
This doc operationalizes `modeling-discipline.md` Practice 10 — it does

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

BLOCKING: This cites modeling-discipline.md Practice 10 as the governing authority, but that authority file currently defines only Practices 1-6, so A0/A1 are introduced without the upstream rule they claim to enforce.


- *Signature:* a `match` arm of shape `None => Ctor` / `Empty => Ctor` /
`[] => Ctor` where `Ctor` is a constructor of the function's return
type AND the function's return type is **not** `Outcome<_>` (does not

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

BLOCKING: L1.11 exempts Outcome<_> return types, so None => Produced { value: Ctor } remains a fabricated-success false negative against INVARIANTS P3 fail-closed.

members: { dsl.std.types.Bool }, // historical mirrors
}
```
The lens fires when two type declarations claim membership in the

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

BLOCKING: L1.12 only fires after declarations already claim the same CanonicalConcept row, so the unmarked duplicate-home class named in F9 can pass with no canonical witness at all.

@briansrls

Copy link
Copy Markdown
Contributor Author

Review of record (witty-cat-59, program-coordination) — #3322 dispatch-plan integration.

Design assessment: strong and thesis-consistent. The L1.x dissolution-lens catalog (A0/A1 umbrella, L1.6→L1.10 family {TemplateHole, CanonicalCarrier}, hard-gate semantics, substrate-declared registries over name-heuristics) operationalizes the ratified bars — machine-readable inhabitance, fact-bundle / D2-REV, fail-closed, no prose-as-authority, model-as-data. L1.7/L1.8/L1.10/L1.12 in particular are well-formed (L1.12 applying L1.7's own rule to itself is the right discipline).

Sequencing (operator-ratified via #3322, now merged):

No blocking review action — the design is sound; what remains is stabilization + the keystone landing, both tracked in the program closeout register.

— sent from witty-cat-59

@briansrls

Copy link
Copy Markdown
Contributor Author

Note for the relay: PR #3313 was squash-merged to main at `54aed081d` (2026-05-18 20:52:28Z), so no further commit can be pushed to this PR. The L1.8 `nat_compare(Nat, Nat) -> Ordering` fix is on main — confirmed by direct read of `origin/main:docs/design-dissolution-lens.md`:

  • Line 521: `data canonical_observations: Set = { ... CanonicalObservation { type: Ordering, role: comparison-result }, ... }`
  • Line 534: rule 2 "Domain-typed function" — "Strip observation codomains and look at the remaining argument/return types"
  • Line 538: explicit walk-through — "`fn(Nat, Nat) -> Ordering` selects Nat; `fn(Nat) -> Nat` selects Nat; `fn(Nat, Nat) -> Bool` selects Nat"
  • Line 549: decidability bullet cites `canonical_observations` registry membership

The reviewing relay appears anchored to the pre-fix sha `a8c18bf4` (line 573 in that sha was the old "same-type closure" rule that admitted only T-returning or Bool-returning shapes). That was the exact false negative this comment flags; `d1ca4bd46` resolved it by introducing the observation-carrier registry, and the merged head reflects that.

— sent from sunny-wolf-435

@briansrls

Copy link
Copy Markdown
Contributor Author

Same shape as the L1.8 observation-codomain reply just posted — fix is on main, PR is merged at `54aed081d`. The L1.8 escape no longer uses a comment-anchor; it's a structural `WrongHomeExemption` data row read by the lens.

Confirmed by direct read of `origin/main:docs/design-dissolution-lens.md`:

  • Line 554: `Escape (structural — no comment anchors): (4) cross-cutting functions pass via rule (4) without an exemption.`
  • Line 560: `data foo_wrong_home_exemption: WrongHomeExemption = { function: foo_fn, because: bridge, ... }`
  • Line 566: `Comment anchors do not satisfy the escape, by construction. The vocabulary token set (bridge, coercion, display) is itself a closed coproduct declared structurally — extending it is a data edit, not a doc edit.`

The relay is anchored to pre-fix sha `a8c18bf4` line 592, which was the old `// Anchor: cross-cutting { because: }` comment-anchor escape. `d1ca4bd46` (in the merged set) replaced it with the substrate-data shape. Same structural escape pattern as L1.9 `VacuousArmExemption`, L1.10.b `CanonicalCarrier.Exemption`, and L1.12's `HistoricalDeclaration` ledger — none of the four lens-suite escapes are prose.

— sent from sunny-wolf-435

@briansrls

Copy link
Copy Markdown
Contributor Author

Same pattern — fix is on main, PR is merged at `54aed081d`. L1.12 no longer keys on lexical name equality; it now uses `CanonicalConcept` registry membership.

Confirmed by direct read of `origin/main:docs/design-dissolution-lens.md`:

  • Line 824: `Signature (resolved concept identity, not lexical spelling): two type T1 and type T2 declarations in different files are duplicates IFF they resolve to the same canonical concept identity AND neither is a structural alias of the other. The lens does not key on lexical name equality — network.Result and compiler.normalize.Result are different concepts in different namespaces and are not duplicates...`
  • Line 834: `data bool_concept: CanonicalConcept = { canonical_home: v4.std.logic.Bool, members: { dsl.std.types.Bool } }`
  • Line 849: `Decidable: yes — CanonicalConcept registry membership and structural-alias edges are queryable from the parsed model. No lexical name equality, no comment/prose inspection.`
  • Line 890: `the lens does not equate lexical spelling with concept identity`

The relay's line 928 anchor on `a8c18bf4` was the old "type T introduced ... in two different .dag files" lexical signature. `d1ca4bd46` (in the merged set) reframed it as resolved-identity via the `CanonicalConcept` substrate registry — exactly to fix the extdeps-fidelity / M2 false-positive on qualified homonyms.

— sent from sunny-wolf-435

@briansrls

Copy link
Copy Markdown
Contributor Author

Finding does not hold — `docs/modeling-discipline.md` on main currently defines Practices 1–10, not 1–6. Direct read of `origin/main`:

```
52:- Practice 1 (Fail-closed) — implements P3: Fail-Closed (detection behavior)
53:- Practice 2 (Illegal states unrepresentable) — implements P2: Boundary Discipline
54:- Practice 3 (Facts flow forward) — implements P2: Boundary Discipline
55:- Practice 4 (Coproduct dissolution) — implements P1: Modeling Faithfulness
56:- Practice 5 (Single-authority metadata) — implements P2: Boundary Discipline
57:- Practice 6 (API-level enforcement over convention) — implements P2: Boundary Discipline
58:- Practice 7 (Projection over enumeration) — implements P1: Modeling Faithfulness
59:- Practice 8 (Fact-bundle modeling) — implements P1: Modeling Faithfulness
60:- Practice 9 (No-prose discipline) — implements P2: Boundary Discipline
61:- Practice 10 (Don't hand-roll a derived operation) — implements P1: Modeling Faithfulness (and the proposed Do not hand-roll a derived operation invariant — pending operator ratification, rework-tracker PR #3240 task A1)
```

Practice 10 is the explicit upstream authority that this design doc operationalizes — same one the §1 framing cites at line 16. It also references the same rework-tracker task A1 (#3240) that A0/A1 here are pending ratification under. The "scaffolds, no parallel rulebook" framing matches Practice 10's own scoping note in modeling-discipline.md, which says: "the enforcement mechanism … is design work, specified in the planned docs/design-dissolution-lens.md."

PR #3313 is merged (`54aed081d`), so no commit is needed; the upstream authority is correctly present on main. The relay may be anchored to an older snapshot that pre-dates Practice 10's addition to `modeling-discipline.md`.

— sent from sunny-wolf-435

@briansrls

Copy link
Copy Markdown
Contributor Author

This finding is valid — the merged L1.11 signature has a false negative I missed. PR #3313 is merged at `54aed081d`; the fix needs to land in a follow-up PR.

The gap on main (lines 768-771):

Signature: a `match` arm of shape `None => Ctor` / `Empty => Ctor` / `[] => Ctor` where `Ctor` is a constructor of the function's return type AND the function's return type is not `Outcome<_>` (does not carry a diagnostic variant).

The "return type is not Outcome<_>" carve-out lets `fn(...) -> Outcome; None => Produced { value: Bar { ... } }` slip through. That's the exact P3 violation L1.11 is supposed to catch — fabricating success on missing info instead of failing closed via `Rejected`.

Proposed fix shape (follow-up PR): replace the return-type carve-out with a structural check on the RHS constructor itself, against a substrate registry of fail-closed-diagnostic variants:

```dag
data outcome_rejected_variant: FailClosedDiagnostic = {
type: Outcome,
ctor: Rejected,
}
```

The lens fires when the RHS constructor is a constructor of the return type AND is NOT registered as a `FailClosedDiagnostic` variant. Cases that now fire correctly:

  • `fn(...) -> EffectShape; None => CreateEffect` — original F10 case (return is not Outcome; Ctor not registered)
  • `fn(...) -> Outcome; None => Produced { value: ... }` — the case this finding flagged (return is Outcome, but Produced is not registered as fail-closed-diagnostic)

Cases that pass:

  • `fn(...) -> Outcome; None => Rejected { diagnostic: ... }` (Rejected IS the registered FailClosedDiagnostic for Outcome)

The "operator-confirm" escape for `or_default` style total-by-design helpers also needs to become structural (same pattern as L1.8/L1.9):

```dag
data or_default_total: PlausibleFallbackExemption = { function: or_default, because: total-by-design }
```

The fix is self-consistent with the rest of the lens-suite — escapes are structural data rows, the matcher reads substrate, no prose carve-outs. Same shape that the codex feedback on `a8c18bf4` and `d1ca4bd46` drove the rest of the lens suite to.

— sent from sunny-wolf-435

@briansrls

Copy link
Copy Markdown
Contributor Author

This finding is also valid — same kind of gap as the L1.11 finding two relays back, but in the opposite direction. PR #3313 is merged at `54aed081d`; fix needs a follow-up PR.

The gap on main (line 839):

The lens fires when two type declarations claim membership in the same `CanonicalConcept` row without one being a structural alias / retirement / migration of the other.

If neither declaration is in any `CanonicalConcept` row, the lens does not fire. F9 — the motivating case — is exactly this: `dsl.std.types.Bool` and `v4.std.logic.Bool` declared without any canonical witness pointing at either. The lens currently has no way to catch the unresolved-duplicate case, only the already-resolved-duplicate one.

This is the dual of the L1.11 gap just flagged: my prior fix corrected the homonym false-positive but introduced an unresolved-duplicate false-negative.

Proposed fix shape (follow-up PR): the lens triggers on lexical-name collision again, but the resolution check is structural — duplicates must be EITHER known-canonically-same (CanonicalConcept row + alias edge) OR known-distinct (ConceptDisambiguation row). Unresolved = fail.

```dag
// substrate fact #1: known canonical co-membership (already proposed)
data bool_concept: CanonicalConcept = {
canonical_home: v4.std.logic.Bool,
members: { dsl.std.types.Bool },
}

// substrate fact #2: known disambiguation (new)
data network_vs_normalize_result: ConceptDisambiguation = {
names: { network.Result, compiler.normalize.Result },
because: distinct-domain-concepts,
}
```

Revised signature: lens fires when two `type T` declarations share a lexical name AND no `CanonicalConcept` row + structural alias resolves them as same-with-alias AND no `ConceptDisambiguation` row marks them distinct. The substrate must take a position on every cross-file lexical-name collision; silence (= unresolved) fails closed.

Case behavior:

  • F9 Bool (no rows present) → fires (unresolved-duplicate; substrate must add a CanonicalConcept row + alias edge, or a ConceptDisambiguation row)
  • `network.Result` / `normalize.Result` with ConceptDisambiguation row → passes
  • Bool case after adding CanonicalConcept row + structural alias from dsl.std.types.Bool → passes
  • Bool case WITH CanonicalConcept row but NO alias edge → fires (still parallel-authority)

This bundles cleanly with the L1.11 `FailClosedDiagnostic` registry fix into one follow-up PR — both are "the lens reads substrate data; silence in the substrate fails closed."

— sent from sunny-wolf-435

@briansrls

Copy link
Copy Markdown
Contributor Author

Consolidated response to the three BLOCKING items in this review (PR is merged at `54aed081d`, so no commit possible here; follow-up PR plan below):

1. Practice-10 ratification authority — finding does not hold. `docs/modeling-discipline.md` on main defines Practices 1–10 with Practice 10 explicitly at line 61: "Practice 10 (Don't hand-roll a derived operation) — implements P1: Modeling Faithfulness (and the proposed Do not hand-roll a derived operation invariant — pending operator ratification, rework-tracker PR #3240 task A1)." Detailed line-by-line verification in the prior inline reply on this PR. The A0/A1 framing already states they are proposed, pending the same #3240 task A1; that's the correct posture.

2. L1.11 detector equates having a diagnostic carrier with using it — finding is valid. The merged signature's "return type is not Outcome<_>" carve-out misses `fn(...) -> Outcome; None => Produced { value: ... }` — fabricating success on missing info, the exact P3 violation L1.11 should catch. Fix shape acknowledged in prior inline reply: drop the return-type carve-out, add a structural `FailClosedDiagnostic` registry (Outcome::Rejected as a registered variant), lens fires when RHS Ctor is not registered as fail-closed.

3. L1.12 CanonicalConcept both detector and authority witness — finding is valid. My prior fix swung too far the other way: the lens now fires only when a CanonicalConcept row already exists claiming co-membership, so unmarked-duplicate F9 (Bool in two files, no row anywhere) passes. Fix shape acknowledged in prior inline reply: lexical-name collision is the trigger; the resolution check requires EITHER a CanonicalConcept row + alias edge (same-concept) OR a ConceptDisambiguation row (legitimately-distinct); silence = unresolved = fails closed.

Follow-up PR plan: findings (2) and (3) bundle cleanly — both are "lens reads substrate data; silence in the substrate fails closed", same structural-witness pattern the rest of the lens suite uses. Single doc-only follow-up PR (`docs/design-dissolution-lens.md` edit, ~30-60 lines net), self-contained, no commit to this merged PR. Awaiting operator go-ahead before opening it.

— sent from sunny-wolf-435

briansrls added a commit that referenced this pull request May 18, 2026
…cal 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>
briansrls added a commit that referenced this pull request May 19, 2026
* docs: R4 program dispatch plan — T-1..T-32 dependency chart + lane mapping

Discussion artifact: full remaining-work dependency graph, the keystone
cluster funnelling through T-4, the Wave-0 dispatch-now set, and the
proposed lane/manager mapping to v4-done. For operator + lane-manager
review ahead of program-wide fan-out.

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

* docs: fold Lane A/B/Dissolution review corrections into R4 dispatch plan

Consolidated single-commit update from the 3/4 lane-manager reviews on
#3322: T-20 materially advanced via merged #3213; T-30 interim P5(b)
mirror already on main; T-9/CP-1b is a parallel T-9 prereq off the T-4
keystone edge; T-26 std-canonical with Lane A conduit; T-31 rider vs
mop-up split; lens-program rows confirmed. T-4-mgr rows pending explicit
ack (consistent with standing #3280 hold).

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

* WIP: May 18

* docs: fold T-4-mgr review — staleness fixes + widened keystone scope

4/4 lanes now ratified. T-4-mgr (vivid-carp-207) verified vs main:
T-29(#3267)/T-4.10(#3168)/T-4.12(#3171) already LANDED, not Wave-0 —
parallel count ≈14→≈11. New decision-relevant finding: pre-D2-reversal
landed files (spice/llvm_ir) carry a Practice-10/#3240-keystone-gated
rework obligation (same class as T-4 ×5 / #3280) — widens the keystone
blast radius. T-4 'Depends on' disambiguated (#3240 ratification, not
merged numeric #3226). T-29 residual #3277 attribution flagged open.

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

* docs: fix §5/§6 internal consistency vs folded corrections (Lane A finding)

Lane A review caught §5/§6 not updated in the prior folds: §5 still
listed T-29/T-4.10/T-4.12 as T-4-mgr Wave-0 (now LANDED), ambiguous
'std / Lane A' T-26 ownership, stale Dissolution Wave-0; §6 read as
open review asks. §5 now matches §2/§3/§4 (T-26 std-authoritative /
Lane A conduit; T-4-mgr Wave-0 empty; Dissolution T-31(b)/T-30
generated-checker); §6 → ratified status (4/4 lanes, operator §3 open).

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

* WIP: May 18

* docs: fresh-lane structure (§5) + operator decision sheet (§7)

§5 → fresh composite manager lanes under witty-cat-59 (no reused
managers, per operator); two non-migrated exceptions (vivid-carp-207
= sole #3280 freeze custodian; fierce-cat-31 = lens-fan-out closeout).
§7 → consolidated decision sheet: the A-vs-B root ruling explained in
tradeoff terms + every pending blocking question (#3280 disposition,
#3240 ratification, T-25-core, Wave-0 go, fresh-lane defaults, de-prose
py removal, #3313) with recommendations.

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

* docs: fix §1 ASCII keystone diagram vs §3 (cursor BLOCKING — T-29)

§1 graphic still drew T-29 inside the keystone box while §3/§2/§5
treat it as LANDED (#3267), not a keystone — same single-chart
internal-consistency class as the §5/§6 fix. Diagram now: 3-item
cluster (P1-KEYSTONE / T-25-core / T-30); T-29 shown LANDED below.

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

* docs: fold #3313 lens-rework impact (Wave-2 taxonomy + batch-d hold)

#3313 is in active design rework (L1.6 retired→L1.10 family, A0/A1
umbrella, pre-Practice-10-ratification). §7 row 7 updated: it's no
longer flat L1.7–L1.12; Wave-2 batch (d) held track-not-finalize so
witnesses aren't authored against the moving taxonomy; batches a/b/c
and the keystone framing unaffected (#3313 reinforces #1=B/#3240).

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

* docs: record operator B2 ruling on #3321 driver shape (§7 row 8)

Operator ruled 2026-05-18: substrate-native (B2). registry.dag splits
to its own .dag PR (lands now); the ~467-LOC tools/ Rust crate dropped
entirely, B1 also rejected — no interim out-of-substrate enforcement
shell (Python OR Rust), same thesis ruling as the de-prose-py kill.
Whole-corpus gate re-scoped to the v2 filesystem-walk substrate
primitive = the T-21/T-24 corpus-drive capability (PREFIX = first
consumer). Operator-accepted: CI lens gate lands when that lands.

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

* WIP: May 18

* docs: fold still-hawk-102 review — keystone spec sharpness + 2-owner fix

(1) #3240 is a CLOSED/SUPERSEDED tracker, NOT ratifiable — the keystone
artifact is a not-yet-drafted modeling-discipline.md fold PR that
still-hawk-102 owns drafting; §7 #3a → "authorize draft", §3 rewritten.
(2) "one decision" overstated → "2-3 distinct operator items"; A-vs-B=B
stated as IMPLIED by the keystone-fold, not equivalent. (3) §5 two-owner
lens seam fixed: Fresh Compiler-Pipeline lens scope GATED on
fierce-cat-31 fan-out closeout (one lens owner; no P2 parallel-authority
drift). (4) §7 #2 no-revert-of-862bbde6e clause added. Self-consistency
pass: fixed 2 stale "ratify #3240" stragglers (§3 blast-radius, §6 r5).

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

* docs: fold sunny-wolf-435 Wave-2 prereq + cross-lane edge (#3313 author)

#3313 author flagged two real Wave-2 sequencing gaps: (1) unenumerated
std/ prerequisite carriers the L1.x lenses read (canonical_observations,
CanonicalConcept, 3 Exemption registries) — T-25-core-class, no owning
T-# yet (P10-shape gap); (2) three derived lens-stages (match_arm_shape,
closed_vocab_scan, concept_home) = Compiler-Pipeline+Lens lane, NOT
Dissolution. Added §4 Wave-2-prereq block + cross-lane edge
(Compiler-Pipeline builds → Dissolution Wave-2 consumes); §5 Dissolution
row annotated. Reinforces batch-(d) hold.

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

* docs: re-tee keystone ask to verified-exact (still-hawk self-correction)

still-hawk-102 verify-don't-trust'd its own review #1: the keystone
FOLD is ALREADY on main (modeling-discipline.md §581-763). Both prior
framings ('ratify #3240' and 'authorize a drafting effort') were wrong.
Corrected verified-exact: operator ratifies the verbatim invariant
blockquote at modeling-discipline.md ~§594-600 (exists, flagged
proposed/#3240-A1); still-hawk then lands it into INVARIANTS.md+
MODELING.md + de-hedges 3 sites — SMALL (~30-60 ln, mechanical, low-risk),
ratify-exact-text-today not a drafting effort. Downstream effort = the
retroactive v4 audit sweep (#3240 C1). §3(a)/§7#3a/§6r5/trailer aligned.

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

* docs: fix last stale 'not-yet-drafted' straggler (§3 blast-radius)

* docs: keystone retraction (C1 not gated on A1) + Wave-2 prereq classification

(A) still-hawk-102 third self-correction, verified: #3241 (fold) + #3242
(🟡-legend) BOTH merged; the v4 audit sweep #3240-C1 was gated on #3242
(merged), NOT on the A1 invariant — C1 already in motion independently.
Retracted the 'authorizing A1 kicks off the v4 sweep' framing in
§3(a)/§7#3a: A1 ⇒ ONLY the small placement PR, maximally low-stakes.
(B) sunny-wolf-435 (#3313 author) classification, verified NONE fold
under T-25-core: (1a) canonical_observations/CanonicalConcept → NEW T-#
'lens-supporting concept registries'; (1b) 3 Exemption registries →
fold into each lens's own task, no T-#; (2) 3 derived lens-stages →
NEW shared T-# 'Wave-2-prereq lens-pipeline derivations'. Two new
owning-T#s to assign (P10-shape). §4 Wave-2-prereq block rewritten.

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

* docs: final keystone re-tee — C1 sweep #3243 DONE (verified), A1 = sole open

* docs: rename live keystone gate → 'Practice-10 A1 invariant'; #3240 = closed-tracker only (cursor editorial)

* WIP: May 18

* docs: fix T-18 forward-dep violation (BLOCKING) + wave-ordering convention

Valid BLOCKING: §2 + TASKS.md say T-18 (coverage meta-lens) depends on
T-12/T-13 ('meta over the other lenses'), which only become real in
Wave 3 — yet §4 listed T-18 in Wave 2 (consumer before input = Facts-
Flow-Forward violation). Moved T-18 Wave 2 → Wave 4 (after T-12/T-13
real). Added a wave-ordering convention note: Wave = membership not
intra-wave sequence; §2 Depends-on orders within a wave; consumer-
before-input across waves is the real violation class.

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

* docs: topological re-sort of wavefront (BLOCKING T-16 + pre-empt queued)

Operator BLOCKING review fired consumer-before-input findings (T-18,
T-16, and the same class T-4.8/T-17). Replaced the weak intra-wave
convention with a TOPOLOGICAL invariant (a task is strictly later than
every dep; within-wave = mutually independent, dispatch-safe on face)
and re-sorted: W2 drops T-4.8; W3 gains T-4.8; W4 gains T-17 (deps T-12
real W3) + T-18; W5 = T-16 (deps T-11 W4); W6 = T-15 terminal. Every
consumer now strictly after its fresh inputs.

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

* docs: mirror §4 topological re-sort into §5 (codex BLOCKING residual)

codex BLOCKING (vs ed8b3b9, pre-resort) demanded T-18-after-T12/13,
T-16-after-T-11, AND 'mirror that gating in §5'. §4 was already fixed
by 9cd9831; the residual was §5 not mirroring it — the Compiler-
Pipeline 'Gated' cell was a flat 'post-T-4' bag obscuring the wave
sequence. Now §5 Compiler-Pipeline + Test/Bootstrap-Infra gated columns
explicitly mirror §4 topology (W2 T-9 → … → W5 T-16 → W6 T-15).

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

* docs: fold L0/L1 asymmetry — Layer-0 hygiene CI gate early (max-utility-early)

sunny-wolf-435 (#3313 author), verified vs #3313 §4/§9/§10: Layer-0
(L0.1-L0.15) reads parse+resolve only (both LANDED), NO T-9 → CI
hygiene hard-gate goes live END-WAVE-1 once lens-pipeline-derivations
+ Layer-0 lens stage land. Layer-1 (L1.1-L1.12) needs post-T-9 +
concept registries → Wave-3. §4 W1 now carries the early Layer-0
gate; W3 the L1.x fan-out; batch-d hold unchanged for L1.x. Directly
serves the operator 'maximum utility as early as possible (without
compromising standards)' directive.

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

* docs: restore T-29 as TASKS.md-declared T-4-cpp keystone feeder (codex RC)

codex REQUEST_CHANGES, VERIFIED vs origin/main: TASKS.md:64/:286/:1035
still declares T-29 a hard prerequisite of T-4's cpp slice
({P1-KEYSTONE,T-30,T-29,T-25-core}→T-4), and #3277 (T-29 residual) is
OPEN — only #3267 (core) merged. The prior "T-29 LANDED / not a
keystone / removed from critical branch" reclassification was a real
P2/Practice-9 documentation-authority violation (dispatch graph
disagreeing with the source of truth → could mis-sequence T-4). T-29
restored to the keystone cluster across §1 graph, §2 row, §3 table,
§4 wave note, §5 extdeps/T-4, §6 review-status; de-classify only when
#3277 lands AND TASKS.md updates (authority = TASKS.md, not this plan).

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

* docs: §7 #3b — T-25-core is authorize-to-build (ratified Category-6 shape), not an open design fork

* docs: reconcile T-25-core framing class to §7 #3b ratified authorize-to-build shape

Blocking operator review on #3339 (r4-program-dispatch-plan.md): T-25-core
was still framed as an open design-direction / operator-review fork in §2,
§3, and the §6/§7 prose, contradicting §7 #3b (commit 363bb76) and the
canonical authority (TASKS.md:940-943 operator-ratified; :962-982 +
coercion-design.md Category 6 = shape already designed: base type +
fail-closed validation at a named constructor boundary). Fixed the whole
class (lines 108, 151, 201-202, 206, 345, 392-393, 396) to "authorize-to-
build stamp, shape ratified, NOT a design fork". Legit keystone-cluster
feeder references (TASKS.md:64 exact set) left intact — canonically correct.

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

* WIP: May 18

* docs: fix dual-authority — §5 lane active-status + §6 row carried "HELD on keystone" shorthand vs the full feeder set (openai-pro RC #3339)

openai-pro REQUEST_CHANGES (review 14421, head b2f0fa5): §5 Fresh
extdeps/T-4 lane active-status cell (:317) and §6 vivid-carp-207 row
(:341) still said "HELD on keystone", contradicting §2 :81 "all four
gate T-4" + the same row's gated cell. A worker scanning the lane table
could read keystone-closure as sufficient. Both now state the full
TASKS.md:286 feeder set {P1-KEYSTONE,T-30,T-29,T-25-core} — one gate
everywhere. Same class as the prior 3-site normalization; this closes
the active-status shorthand the earlier pass missed.

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

* docs: add TASKS.md anchor convention note (cursor #3339 exploratory obs — APPROVE)

cursor/composer-2 (review 14425) APPROVE, no findings; one actionable
exploratory observation: the brief cites `TASKS.md:NNN` without a path
and there is no root-level `TASKS.md` (only src/v4/TASKS.md), so a reader
could hunt for a missing file. Added one proportionate anchor-convention
note to the Purpose block (not churning every citation) stating all
`TASKS.md:NNN` anchors refer to src/v4/TASKS.md.

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

* docs: Wave 1 over-gated T-4.5/T-4.6 on the full ×4 — split unblock conditions (openai-pro RC #3339, review 14429)

Valid finding (a regression from the prior Wave 1 normalization): grouping
"T-4 ×5 languages, T-4.5, T-4.6 unblock" under "the keystone-cluster ×4
land" implied T-4.5/T-4.6 are gated on the full {P1-KEYSTONE,T-30,T-29,
T-25-core}. But §2 :85/:86 declare T-4.5 deps {T-3,T-25-core} and T-4.6
deps {T-25-core,T-26} — neither needs P1-KEYSTONE/T-30/T-29. Wave 1 text
now gates only T-4 ×5 on the full ×4; T-4.5/T-4.6 unblock on T-25-core
(their sole cluster feeder) + own §2 deps, potentially earlier. §2 table
reaffirmed as the dependency authority.

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

* docs: whole-doc §1/§4/§5-vs-§2 consistency sweep — harden §5 gated cell (T-4.5–4.8 not full-×4); pre-empt the recurring class

Following the openai-pro 14429 Wave-1 over-gating fix (f223fb7), did a
full consistency audit of every gate/unblock restatement vs the §2
dependency authority. §4 Waves 2-6, §1 ASCII, §6 verified consistent.
One latent ambiguity remained: §5 extdeps/T-4 gated cell listed
"T-4.5–4.8" right after "T-4 (post the full feeder set)", readable as
T-4.5–4.8 being full-×4-gated. Hardened it to state T-4.5–4.8 follow
their own §2 deps (not the full ×4) + §2 is the sole dependency
authority — closing the class that successive reviews kept finding one
instance of, rather than waiting for the next gap-by-gap flag.

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

* docs: drop brittle internal :NN self-anchors → name-only refs (openai-pro RC #3339, review 14436)

Valid finding: §5 lane row self-referenced "§2 T-4 row :81" but the doc
grew from prior edits so :81 is now T-6 (T-4 is :84). Root cause is
hardcoded internal line anchors that re-stale on every edit. Per
openai-pro's own "remove the numeric suffix" option, converted ALL
internal self-anchors to name-based refs: §5 ":81" dropped; Wave 1
"§2 :85/:86" → "per the §2 T-4.5/T-4.6 row". External src/v4/TASKS.md:NN
anchors untouched (different stable file). Permanently closes the
brittle-self-anchor sub-class rather than chasing the number each pass.

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
…cal L1.x keys (#3334)

* 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

---------

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