Files
sx/docs/fork-c/S0.2-e6b-disposition-and-two-corpus-partition.md
agra ca8bc85120 docs(fork-c/S0): correct two doc-accuracy lines (base-equivalence wording + grounded FFI count)
attempt-2 review fixes (docs-only; contract mechanics confirmed sound):
- README + S0.2 grep-clean: 'S0 HEAD == base' / 'S0 == base' were inaccurate
  (HEAD carries the docs/examples/tests diff). Reword to: production/compiler
  behavior is base-equivalent — zero src/ changes, single-author output
  byte-identical to base by construction — HEAD is a distinct commit, not base.
- S0.3 ledger: drop the stale '116-class corpus' FFI wording for the grounded
  live count (96 entry trees / 95 active markers), matching the S0.1 count note.

No partition / manifest / examples / harness change. Gate green:
zig build + zig build test (LSP sweep 574, no crash) + run_examples (540/0);
m3te ios-sim build via main binary exit 0.
2026-06-09 10:47:42 +03:00

144 lines
8.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 — `src/` is base-equivalent, zero src changes):**
| 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.