docs(fork-c/S0): setup contract — byte-baseline + commit-discipline, E6b disposition + two-corpus partition, A–E6 reuse/delete ledger

S0 of the ratified Fork C plan (zero-legacy name-resolution redesign, S0→S6).
Pure setup/documentation: NO production code change, NO behavior change.
Single-author output byte-identical to wt-stdlib-base by construction.

Deliverables under docs/fork-c/ (docs/, not current/, because current/ is
gitignored and the contract must be committed):

S0.1 — byte-baseline + commit-discipline: the committed examples/expected/*
snapshots are the single-author byte-identity reference; the zero-diff repro is
`zig build && zig build test && bash tests/run_examples.sh`. Resolver-target set
explicitly excluded + listed. Commit-classification rule: mirror | consumer-cutover | deletion.

S0.2 — E6b disposition + two-corpus partition: transitional E6b src NOT merged
(grep-clean: no resolveRegistrationSigTypeInSource / sig_registration_mode /
e6br_gate.test.zig on baseline). Harvested 0811–0829 trees + goldens (never the
src), empirically partitioned by running each through the base compiler vs the
E6b target:
  - baseline-green (mirror-equivalence): 0795–0798 (merged) + 0823, 0828 — given
    examples/expected/ markers, locked into the S0 baseline.
  - resolver-target (known-wrong old behavior): 0811–0822, 0824–0827, 0829 + the
    re-filed E6BR-5 nested-pattern regression — a listed xfail harness under
    tests/resolver-target/ (manifest + TARGET goldens, NO active marker), flips
    active+green at S3.9. 0811/0829 noted as old-selector-wrong on the E6b-unmerged
    base; E6BR-5 subsumed by the whole-AST resolver, NOT an E6b attempt-6.

S0.3 — A–E6 reuse/delete ledger: every load-bearing A–E6 artifact mapped REUSED
(Fork C home) or DELETED/TRANSITIONAL (S3/S6 phase); E6c/d/e dropped, F/H/I/K
absorbed/superseded.

Gate over the baseline-green corpus: zig build + zig build test (LSP corpus sweep
574 files, no crash) + bash tests/run_examples.sh (540 passed, 0 failed) all exit 0.
This commit is contained in:
agra
2026-06-09 10:29:23 +03:00
parent 1f755284d9
commit 1ce3a4e9e0
114 changed files with 1584 additions and 0 deletions

57
docs/fork-c/README.md Normal file
View File

@@ -0,0 +1,57 @@
# Fork C — setup contract (S0)
Zero-legacy name-resolution redesign (S0→S6), replacing E6cK. This directory is the
**committed S0 contract** the remaining 26 steps (S1→S6) execute against. It is pure
setup/documentation — **S0 introduces no production code change and no behavior
change**; single-author output is byte-identical to `wt-stdlib-base` by construction.
**Authority:** `runs/stdlib/design/fork-c-deepdive/reconciled.md` (§5 by-construction
audit, §6 staged roadmap + deletion lists, §8 fold-in) and
`runs/stdlib/design/fork-c-plan/planspec-r3.json` (the S0.1/S0.2/S0.3 intent +
acceptance, Adi-confirmed — they govern).
## Doc-area decision
Deliverables live under **`docs/fork-c/`**, NOT `current/fork-c/`. Reason: `current/`
is **gitignored** in this repo (`.gitignore``current/`), so a new `current/fork-c/`
tree would not be committed; the S0 contract must be committed. `docs/` is tracked.
## Baseline
- **Base:** `wt-stdlib-base @ 1f755284d98c6e8ebba953045c06e35d8cbe6278` (AE6a merged).
- **E6b:** `flow/stdlib/E6b @ af737b0` — PAUSED, **unmerged**, all transitional, destined
for S3/S6 deletion. Its semantics goldens are harvested; its src is never merged.
- **This branch:** `flow/stdlib/S0` (branched from the base; S0 HEAD == base).
## Contents
| file | sub-step | what |
|---|---|---|
| `S0.1-byte-baseline-and-commit-discipline.md` | S0.1 | the byte-identity reference + the zero-diff reproduction command + resolver-target exclusion + the `mirror \| consumer-cutover \| deletion` commit-classification discipline |
| `S0.2-e6b-disposition-and-two-corpus-partition.md` | S0.2 | E6b src not merged (grep-clean) + the harvested corpus partitioned baseline-green vs resolver-target + 0811/0829 placement + the E6BR-5 re-file + the mirror/flip statement |
| `S0.3-reuse-delete-ledger.md` | S0.3 | every load-bearing AE6 artifact mapped REUSED (Fork C home) or DELETED/TRANSITIONAL (S3/S6 phase); E6c/d/e dropped, F/H/I/K absorbed/superseded |
| `../../tests/resolver-target/` | S0.2 | the listed resolver-target harness: `manifest.md` (18 cases), `expected/` TARGET goldens, the E6BR-5 reproducer under `cases/`, and `run_resolver_target.sh` (xfail runner — NOT part of the gate) |
## The two-corpus law (the one thing the next 26 steps must never conflate)
1. **BASELINE-GREEN / mirror-equivalence corpus** — tests where the old selector is
already correct today (AE6a merged + the 6 harvested baseline-green cases + FFI
12xx14xx + the LSP smoke). Stays **green and single-author byte-identical at every
step S0→S6**, and is the S2 assert-only Debug mirror's **only** oracle.
2. **RESOLVER-TARGET corpus** — harvested goldens that encode **known-wrong old
behavior** (silent resolve / under-diagnose / wrong author / own-wins-fails) + the
E6BR-5 regression. Held **inactive/xfail** (listed, never silently dropped) from S0
through S3.8, then **flips to active + green at S3.9** against its TARGET output —
never against the old selectors (a wrong oracle for it on the E6b-unmerged base).
## Gate (this branch)
```sh
export PATH="$HOME/.zvm/bin:$PATH"
zig build && zig build test && bash tests/run_examples.sh # exit 0 over the baseline-green corpus
```
Since S0 changes no production code, single-author output is byte-identical by
construction. The resolver-target xfail diagnostic
(`bash tests/resolver-target/run_resolver_target.sh`) is separate and not part of the
gate.

View File

@@ -0,0 +1,102 @@
# S0.1 — Byte-baseline (baseline-green only) + commit-classification discipline
Authority: `runs/stdlib/design/fork-c-plan/planspec-r3.json` (S0.1) +
`runs/stdlib/design/fork-c-deepdive/reconciled.md` (§6 green-lock). Base:
`wt-stdlib-base @ 1f755284d98c6e8ebba953045c06e35d8cbe6278` (AE6a merged). This is
documentation only — no production code change, no behavior change.
## 1. The byte-identity reference
The single-author byte-identity reference that **every later Fork C commit is checked
against** is the committed `examples/expected/*` snapshot set on the baseline commit
above. We do **not** copy every file into this doc; the snapshots ARE the reference,
and the reproduction is a documented zero-diff command (§2). Single-author byte
identity is held structurally by `nominal_id == 0 ≡ structural intern`
(`src/ir/types.zig` `internNominal`), which S1S2 keep additive and S3 preserves
through ordinal-0 materialization.
The baseline-green corpus that the reference covers:
| segment | what | how it is exercised | count @ S0 |
|---|---|---|---|
| baseline-green examples | every `examples/<name>.sx` with an active `examples/expected/<name>.exit` marker (incl. the 6 harvested baseline-green cases `07950798`, `0823`, `0828`) | `bash tests/run_examples.sh` | **540** active markers |
| FFI corpus | `examples/12xx14xx` (96 entry trees; 95 with active markers; ~418 files incl. module/`.c`/`.h`/`.m` companions) | same runner (markers) | 95 active markers |
| LSP completion/hover smoke | LSP unit tests under `zig build test``analyzeDocument` flat/namespaced import + the `lsp corpus sweep: every examples/*.sx analyzes without panicking` sweep + definition/references/inlayHint | `zig build test` | — |
> Count note: `reconciled.md §1` cites "116 files in `examples/12xx14xx`". The live
> tree has **96 entry `.sx` trees** (95 with active markers); the "116" is a stale
> historical figure. What is load-bearing is the invariant — *all FFI 12xx14xx
> examples stay byte-stable* — which `run_examples.sh` enforces via their markers,
> not the exact historical count.
## 2. The zero-diff reproduction method
`tests/run_examples.sh` runs `sx run <entry>` for every `<name>.sx` that has an
`expected/<name>.exit` marker, normalizes stdout/stderr identically for expected and
actual (address hashing → `0xADDR`; absolute `…/examples|issues/` paths → repo-relative),
and diffs exit + stdout + stderr (+ optional `.ir`). A **zero-diff** run is the
byte-identity check:
```sh
export PATH="$HOME/.zvm/bin:$PATH"
zig build # build the compiler under test
zig build test # unit tests incl. the LSP completion/hover smoke + corpus sweep
bash tests/run_examples.sh # must print "<N> passed, 0 failed, 0 skipped*, 0 timed out"
```
Any later commit whose single-author output drifts shows up as a `FAIL` with a printed
diff. `tests/run_examples.sh --update` regenerates the snapshots — it must **only** be
run intentionally when a commit's classification (§3) authorizes an output change, and
the diff reviewed. (* `skipped` counts `.exit` markers whose `.sx` is absent; it is 0
on a clean tree.)
## 3. Resolver-target EXCLUSION (recorded, not silently absent)
The **resolver-target set** is **excluded from both** the byte-baseline AND the active
`run_examples.sh` set, because it encodes known-wrong old behavior (silent resolve /
exit 0 / under-diagnosis / wrong author) — a stale old-selector verdict must never
enter the baseline as if it were correct. The exclusion is explicit and **listed**, not
absent:
- the 17 harvested `08xx` resolver-target cases (`0811, 0812, 0813, 0814, 0815, 0816,
0817, 0818, 0819, 0820, 0821, 0822, 0824, 0825, 0826, 0827, 0829`) + the re-filed
**E6BR-5** regression;
- enumerated in `tests/resolver-target/manifest.md`, with TARGET goldens in
`tests/resolver-target/expected/`, held inactive (no `examples/expected/` marker) and
asserted currently-failing by `tests/resolver-target/run_resolver_target.sh`;
- full disposition in `S0.2-e6b-disposition-and-two-corpus-partition.md`.
They flip to active + green at **S3.9** and only then join the baseline.
## 4. Commit-classification discipline
Every future Fork C migration commit (S1→S6) is tagged with exactly one of three
classes, stated in the commit subject/body so a reviewer knows what byte-effect to
expect:
| tag | meaning | expected byte-effect on the baseline-green corpus |
|---|---|---|
| **`mirror`** | builds new facts / a new resolver path **in parallel**, while lowering still consumes the old path (S1S2; the assert-only Debug mirror) | **zero** — single-author output byte-identical; provably zero byte-risk |
| **`consumer-cutover`** | switches a consumer from the old path to the resolved facts (S3 materializer / calls / consts / protocol-registration / `#using`; S5 LSP) | **zero on baseline-green** — byte-identical by ordinal-0 materialization + payload-preserving facts; the only commits that may change resolver-target (the S3.9 flip is a cutover) |
| **`deletion`** | removes a now-dead artifact (old name selectors, `*_by_source` mirrors, `type_bridge`, `findByName`, the grep gate, the S2 mirror) | **zero** — the deleted code had no live readers after its cutover; a surviving reader fails to compile |
Rules:
- A commit is exactly one class; a cutover that also deletes its now-dead source is
still a `consumer-cutover` if the delete is the same atomic cutover (e.g. S3.10
removes the last old selector **and** the S2 mirror in the cutover commit).
- `mirror` and `deletion` commits MUST be byte-zero on baseline-green; if a `mirror`
commit changes a byte, it was not actually parallel — stop.
- Only `consumer-cutover` may legitimately change output, and only the **resolver-target**
corpus (never baseline-green) — that is the S3.9 flip.
## 5. Acceptance (S0.1) — self-check
- ✅ Byte-baseline of all baseline-green examples + FFI 12xx14xx + LSP smoke captured
and reproducible via the documented zero-diff command (§1§2); the reference is the
committed `examples/expected/*` at the baseline commit, re-checked by a zero-`FAIL`
`run_examples.sh`.
- ✅ Resolver-target set explicitly excluded from the byte-baseline AND the active
`run_examples.sh` set, and recorded/listed (§3) — not silently absent.
- ✅ The `mirror | consumer-cutover | deletion` classification rule is written (§4).
- ✅ `zig build && zig build test && bash tests/run_examples.sh` green over the
baseline-green corpus; no behavior change (S0 adds no production code).

View File

@@ -0,0 +1,143 @@
# S0.2 — E6b disposition, the two-corpus partition, and the E6BR-5 re-file
Authority: `runs/stdlib/design/fork-c-plan/planspec-r3.json` (S0.2) +
`runs/stdlib/design/fork-c-deepdive/reconciled.md` (§3 one-resolver-two-timings, §6
roadmap, §8 fold-in). Base: `wt-stdlib-base @ 1f75528` (AE6a merged). E6b:
`flow/stdlib/E6b @ af737b0` (PAUSED, unmerged). This is documentation only — no
production code change.
## 1. E6b transitional src is NOT merged
The transitional E6b source on `flow/stdlib/E6b @ af737b0` is **not** brought onto the
Fork C baseline. All of it is destined for **S3/S6 deletion** under Fork C:
- the **route-all engine** + the type-reference **choke-point**
(`resolveRegistrationSigTypeInSource` / `sig_registration_mode`) — `lower.zig`,
`protocols.zig`;
- the executable **grep gate** `src/ir/e6br_gate.test.zig` (+ its `ir.zig` import);
- the supporting `calls` / `lower` / `protocols` / `type_bridge` / `type_resolver` /
`types` changes.
Grounded reasons it is transitional, not load-bearing: the whole-AST resolver walks
**every** reference position, so it closes the protocol/param-impl signature surface
the choke-point policed (reconciled §3/§4 T4); and the grep gate is unnecessary once
the leaf it polices no longer exists (reconciled §5). AE6a stays merged purely as
**proof-of-semantics + per-decl nominal infra** (`internNominal` / `nominal_id==0`
byte-identity rule / `RawDeclRef` facts → the `DeclId` seed) — see
`S0.3-reuse-delete-ledger.md`.
**Grep-clean (verified on this branch, S0 == base):**
| check | base / S0 | E6b |
|---|---|---|
| `resolveRegistrationSigTypeInSource` in `src/` | **absent** | present (`lower.zig`) |
| `sig_registration_mode` in `src/` | **absent** | present (`lower.zig`, `protocols.zig`) |
| `src/ir/e6br_gate.test.zig` | **absent** | present |
| `walkConcreteSigArgs` in `src/ir/lower.zig` | **absent** | present (the E6BR-5 site) |
Because S0 introduces **no production code change**, these remain absent on the Fork C
baseline by construction.
## 2. Harvested resolver-acceptance corpus + the two-corpus partition
Harvested by copying the example **trees + their expected goldens ONLY** (never the
transitional src):
- `examples/08110829` (19 trees) from `flow/stdlib/E6b @ af737b0` — error-set /
protocol / param-impl / route-all same-name ambiguity & own-wins surfaces;
- `examples/07950798` (already merged on the base) — the enum/union ambiguous/own-wins
pair.
The corpus is **partitioned by empirically running each harvested case through the
current base compiler and comparing its output to the E6b TARGET golden** (the exact
method: build, then `sx run examples/<name>.sx`, normalize with the
`run_examples.sh` rules, diff against the E6b golden):
### (a) BASELINE-GREEN — the mirror-equivalence corpus
Harvested cases whose **old selector is already CORRECT on `wt-stdlib-base` today**
(actual == E6b target, byte-for-byte). They get standard
`examples/expected/<name>.{exit,stdout,stderr}` markers, are run by
`tests/run_examples.sh`, and are **locked into the S0 baseline**. This set is the S2
assert-only Debug mirror's **ONLY** oracle.
| case | exit | proof it is already-correct on base |
|---|---|---|
| `0795-modules-same-name-enum-ambiguous` | 1 | already merged + green (E6a) |
| `0796-modules-same-name-enum-own-wins` | 0 | already merged + green |
| `0797-modules-same-name-union-ambiguous` | 1 | already merged + green |
| `0798-modules-same-name-union-own-wins` | 0 | already merged + green |
| `0823-route-all-own-wins-subform-wrappers` | 0 | base output == E6b target (`opt=1 arr=2 sl=3 dep=99`) |
| `0828-protocols-param-impl-arg-wrapped-own-wins` | 0 | base output == E6b target (`tag=7 dep=9`) |
### (b) RESOLVER-TARGET — known-wrong old behavior
Harvested cases (and the re-filed E6BR-5) where the **old selector is wrong on the
E6b-unmerged base** (silently resolves last-wins / under-diagnoses / picks the wrong
author / fails own-author resolution). They are held in a **documented, listed,
separate harness** at `tests/resolver-target/` with **NO active `examples/expected/`
marker** (so `run_examples.sh` does not run them), but **WITH** their TARGET output
recorded and an **enumerated manifest** (`tests/resolver-target/manifest.md`, 18
cases). The sibling xfail runner `run_resolver_target.sh` runs each and asserts it
currently FAILS — so the set is **never silently dropped**. It flips to active + green
at **S3.9**.
The 17 harvested `08xx` resolver-target cases: `0811, 0812, 0813, 0814, 0815, 0816,
0817, 0818, 0819, 0820, 0821, 0822, 0824, 0825, 0826, 0827, 0829`. Per-case class,
base-now behavior, and target are in the manifest.
**0811 and 0829 placement (required one-liners):**
- **0811 → resolver-target.** *Old selector is wrong here on the E6b-unmerged base:*
the five bare error-set forms (`size_of` / annotation / type-as-value / match-arm /
`!IoErr` channel) each silently resolved one global last-wins `IoErr` via the
`type_bridge.resolveInlineErrorSet` `findByName` short-circuit and the program exited
0; the target is five loud "type 'IoErr' is ambiguous" diagnostics + exit 1.
- **0829 → resolver-target.** *Old selector is wrong here on the E6b-unmerged base:*
the concrete `*Box` prefix of the mixed pack-closure source fell to the no-author
`type_bridge.resolveTemplateSignatureType` wrapper (global last-wins) and registered
silently (exit 0); the target is a loud `Box` ambiguity + exit 1.
## 3. E6BR-5 re-filed into resolver-target
**E6BR-5** (the open nested-pattern ambiguity hole that paused E6b) is re-filed into
the resolver-target set as a regression — **explicitly NOT an E6b attempt-6.**
- *What it is:* `walkConcreteSigArgs` (E6b `lower.zig:14686`) **skips** any direct arg
that has an unbound part instead of **recursing** into it, so a nested concrete leaf
(`*Box` inside `Closure(Closure(*Box, ..$inner) -> $IR, ..$args) -> $R`) is never
ambiguity-checked; the impl compiled rc=0. On `wt-stdlib-base` (E6BR-4 unmerged) both
the direct and nested concrete leaf silently resolve via the pre-E6BR-4 no-author
wrapper path, so the reproducer exits 0 with no diagnostic.
- *Subsumption (one line):* the whole-AST resolver walks **every** reference position —
including nested parameterized-pattern leaves — so the nested `Box` is
ambiguity-checked by construction and the "skip a nested arg" hole cannot exist.
- *Form:* an authored reproducer lives at
`tests/resolver-target/cases/e6br5-nested-pack-source-ambiguous.sx` (self-contained;
verified to exit 0 silently on the base — the fail-before). Its target is a **spec**
(exit 1 + `Box` ambiguous), with exact bytes produced by the resolver at S3.9
(`expected/e6br5-…target.md`).
## 4. The mirror / flip statement (locked)
- **S2's mirror asserts `resolver == old-selector` over the BASELINE-GREEN corpus
ONLY.** It never asserts new == old over the resolver-target corpus (the old selector
is a wrong oracle there), and it never selects for lowering (assert-only, Debug-only,
deleted in the S3.10 commit that completes the cutover).
- **S3.9 flips the resolver-target corpus to active + green**, validated against each
case's TARGET output (not against the old selectors). After the flip, the goldens
move from `tests/resolver-target/expected/` to `examples/expected/`, the harness goes
empty, and these cases stay green through S6.
## 5. Acceptance (S0.2) — self-check
- ✅ Written disposition: E6b transitional src not merged (§1, grep-clean table).
- ✅ Harvested corpus recorded + partitioned: baseline-green (markers, locked,
mirror-equivalence) vs resolver-target (enumerated manifest, separate listed harness,
no active marker, TARGET goldens present, currently xfail, never dropped) — §2.
- ✅ 0811 and 0829 each in resolver-target with the "old selector is wrong on the
E6b-unmerged base" one-liner — §2.
- ✅ E6BR-5 re-filed into resolver-target with the subsumption one-liner, NOT an E6b
attempt-6 — §3.
- ✅ Mirror/flip statement recorded — §4.
- ✅ No transitional E6b src on the Fork C baseline (grep-clean) — §1.

View File

@@ -0,0 +1,72 @@
# S0.3 — AE6 reuse / delete ledger
Authority: `runs/stdlib/design/fork-c-deepdive/reconciled.md` (§6 roadmap + per-phase
deletion lists, §8 fold-in) + `runs/stdlib/design/migration.md` ("what happens to
already-merged AE6 work") + `planspec-r3.json` (S0.3). Base: `wt-stdlib-base @
1f75528`. Symbol/file refs are grounded against the base tree. This is documentation
only — no code change.
This ledger is the contract the later phases execute against: every load-bearing AE6
artifact is mapped to **REUSED** (with its Fork C home) or **DELETED/TRANSITIONAL**
(with the S3/S6 phase that removes it). AE6a stays merged; the transitional E6b src
is never merged (see `S0.2-…`).
## A. REUSED — AE6 work that becomes Fork C infrastructure
| AE6 artifact (base location) | Fork C home | phase |
|---|---|---|
| **Phase A import facts**`RawDeclRef` / `RawAuthor` / `ModuleDecls` / `NamespaceEdges` (`src/imports.zig`), built in `resolveImports` (`core.zig`) | **seed `DeclId` construction**`DeclTable` keys every `RawDeclRef` into a stable `DeclId` (source + name + AST ptr + `DeclKind`); namespace members get ids | S1 |
| **Phase B visibility**`collectVisibleAuthors` / `collectNamespaceAuthors` (`src/ir/resolver.zig`), "the one graph iterator" over `flat_import_graph`/`namespace_edges` | **resolver internals** — become the resolver's visibility walk, with own-wins / single-flat-visible / ≥2-ambiguous **verdicts above them**, producing `ResolvedRef` | S2 |
| **Phase C callable selection** | **`ResolvedRef.function` / `.type_function`** keyed by `DeclId` | S2 (select) → S3 (consume) |
| **Phase D nominal identity**`internNominal` / `updatePreservingKey` + the **`nominal_id == 0 ≡ structural intern` ordinal-0 byte-identity rule** (`src/ir/types.zig`, `lower.zig`) | **reused inside materialization**`materializeType(ResolvedTypeNode)` interns in old scan order with ordinal 0 for non-colliding decls ⇒ byte-identical single-author output | S3 (+ green-lock every phase) |
| **E-series selection rules** — own-wins / not-visible / ambiguity / direct-flat (the E1E6a behaviors) | **resolver behavior + regression tests** (the baseline-green corpus is the mirror oracle) | S2 behavior; regressions locked S0 |
| **CP rule** — body-author == layout-author | **keyed by `InstantiationId{template_decl, resolved_args}`** in the fact store | S4 |
| **E6BR routed-signature cases** (the E6BR-1…4 behavioral cells) | **resolver-signature regressions** — the resolver walks every signature reference position; cases live in the resolver-target corpus, flip at S3.9 | S3.9 |
| **FFI `foreign_class_map` consumers + 116-class corpus** | parallel `DeclId`s land at S1 (map still the consumer); foreign classes keyed by `DeclId` at S4; runtime names stay **payload strings on facts** | S1 → S4 |
## B. DELETED / TRANSITIONAL — removed in S3/S6
| artifact (base location) | why it goes | removal phase |
|---|---|---|
| **Stateless `type_bridge` leaves**`resolveAstType` / `resolveTypeName` / `resolveInline{Enum,Union,Struct,ErrorSet}` / `resolveParameterizedType` / `resolveErrorType` (`src/ir/type_bridge.zig`); the whole `type_bridge.zig` (E6b renamed the entry leaf `resolveAstTypeNoAuthorSelection`) | no-author `findByName` leaves — replaced by `materializeType(ResolvedTypeNode)` which cannot take a name | selectors S3; file S6 |
| **`TypeResolver.resolveName` / `resolveNamed`** (`src/ir/type_resolver.zig`) (E6b: `resolveNamedGlobalNoAuthorSelection`) | name→global resolution; superseded by the resolver | S3 (name-selection) / S6 (`resolveName*`) |
| **Old name selectors**`selectNominalLeaf`, `resolveNominalLeaf`, `moduleTypeAuthor`, `namedRefTid`, `flatTypeAuthorCount`, `nameAuthoredAsTypeAnywhere`, `selectModuleConst` (+ const-source pins), `selectGenericStructHead`, `headTypeGate`, `headFnLeak`, `flatFnAuthor*`, the name-selection in `resolveTypeCallWithBindings`/`resolveParameterizedWithBindings` (`src/ir/lower.zig`) | the duality leak — replaced by `ResolvedRef`/`ResolvedTypeNode` consumed in lowering | S3 |
| **`*_by_source` mirrors + source pins** (`src/ir/program_index.zig`) + their writers + the `lower.zig` unified writers | dual-write mirrors of the global maps — superseded by the `DeclId`-keyed fact store | S4 |
| **`type_decl_tids`** (`src/ir/types.zig`, `lower.zig`) | name→TypeId mirror — superseded by `DeclId` facts | S4/S6 |
| **`ShadowTypeDecl` / shadow-slot reservation helpers** (`src/ir/lower.zig`) + lower-side nominal selectors | shadow reservation is a name-keyed pre-pass artifact — subsumed by `DeclId` pre-pass | S3/S4 |
| **`TypeTable.findByName` / `findUniqueByName`** (`src/ir/types.zig`) | the global name table — deleted **last** (after the ~15 category-(b) stdlib lookups are re-homed to resolved-once `DeclId`s, per the §6 critical ordering constraint) | S6 |
| **the type-reference choke-point + route-all engine** (`resolveRegistrationSigTypeInSource` / `sig_registration_mode`) | **transitional E6b src — never merged**; destined for deletion under Fork C | S3/S6 (already off-baseline) |
| **the grep gate `e6br_gate.test.zig`** (+ its `ir.zig` import) | **transitional E6b src — never merged**; unnecessary once the leaf it polices is gone | S6 (already off-baseline) |
| **the S2→S3 assert-only Debug mirror** | a test oracle, not a code path — must be deleted in the **same S3.10 commit** that removes the last old selector | S3.10 |
## C. Dropped / absorbed / superseded plan items
- **E6c / E6d / E6e** (protocol / foreign / type-fn per-kind identity): **DROPPED as
steps.** They become resolver behavior + regression tests — a whole-AST resolver
walks every reference position (annotation, `size_of`, dispatch head, `Self`,
vtable), closing the protocol surface the per-kind patch structurally could not
(reconciled §4 T4).
- **F** (namespace resolver + 0104): **ABSORBED** into S2 as resolver internals
(`namespace_edges``ResolvedRef.namespace` / member).
- **H** (constructor heads): **ABSORBED** into S3 `materializeType` over resolved
generic/protocol/type-fn heads.
- **I** (protocol + foreign selection, loud-on-≥2): **ABSORBED** into S2 selection + S4
`DeclId` facts.
- **K** (delete dead readers): **SUPERSEDED** by the S4 `DeclId`-keyed fact store + the
S6 deletions — "just delete the maps" is upgraded to "replace with `DeclId` facts."
- **the per-kind taxonomy**: **REIFIED** as the `ResolvedRef` union itself; the
exhaustive `switch` is the live taxonomy check (the grep gate is gone because the leaf
it policed no longer exists).
## D. Acceptance (S0.3) — self-check
- ✅ Every load-bearing AE6 artifact mapped to REUSED (with Fork C home) or
DELETED/TRANSITIONAL (with the S3/S6 phase that removes it) — tables A & B; covers
Phase A import facts → `DeclId` seed; B `collectVisibleAuthors` → resolver internals;
C callable selection → `ResolvedRef.function/type_function`; D `internNominal` +
ordinal-0 byte-identity → materialization; E-series rules → resolver behavior +
regressions; CP → `InstantiationId`; the stateless `type_bridge`/`type_resolver`
leaves, `*_by_source` mirrors + source pins, `type_decl_tids`/shadow helpers +
lower-side selectors, the choke-point + route-all + grep gate → S3/S6 deletion.
- ✅ States E6c/d/e dropped and F/H/I/K absorbed/superseded — table C.
- ✅ No code change.