The TODO(#11) silent-accept of `for (let (a, a) .. xs)` rested on a
stale premise -- resolvewalk has per-block scopes since #53 and IS
the live w6c_ww checker pass. Bindings now install in a per-LOOP
scope (the N_MCASE pattern), so a duplicate name within one pattern
errs "redeclared in same scope" (cstage parity via stamptuplebinds'
scopedefine-nil check) while sequential same-name loops stay legal.
kwtab restores its stated alphabetical order (`import` before `is`,
both stages, kinds swapped in lockstep with names).
Four seams from one review cluster, all landing on the same checker
files; gates ran on the union (rule 11 body).
?-subset: the wwstage walk compared `...spread` ALIAS nodes on both
sides of the error-subset check, falsely rejecting a spread-carried
error return (`(i64 | ...errs)`, cs-accept/ww-reject) — both sides
now flatten like trycountvariants (cstage Tparams are pre-flattened
at type level).
Multi-let/multi-assign: the tuple gates keyed on the RAW rhs kind,
rejecting a NAMED tuple alias (`type pair = (i64,i64)`; cs clean-
reject, ww asserttyped stop) — both stages chase per #99 alias
transparency, wwstage rettupleof peels the alias so cgmassign keeps
the str element's len/cap stores, and the catA massign-alias error
pin re-rules to a run fixture. The N_MLET diagnostic also printed
its operands swapped (elem/declared reversed vs its wording).
Yield: match_yield_type didn't descend into N_SWITCH, so a yield
inside a switch arm typed the match void and dropped the value
(both stages); and a stray yield outside any match arm reached cgen
unchecked — both stages now gate on a match-arm counter (the
c->loops discipline).
cstage rejects `add(1,2,3)` and `add(4)` (too many / not enough
arguments); wwstage ran no count check at this seam, so both built
-- a stray arg pushed silently, a missing one read garbage
(cs-reject/ww-accept build-verdict divergence). Surplus errs when
params exhaust with args left; missing errs on a leftover regular
param (a leftover TK_ELLIPSIS or FFI "..." is a legal zero-arg
variadic tail). fn-VALUE callees still bail at decl==nil -- their
whole typecheck, arity included, stays task #51.
Two composing defects made a two-enum union mis-tag in wwstage
(live cs!=ww: `let e: (color|shape) = shape.BALL` stored tag 0 —
the color arm — while cstage stored 1). type_eq/typeeq had no
TY_ENUM arm, so ANY two enums fell into the primitive default and
compared equal; enums are nominal (harec: an enum IS its alias
type) and now compare by node identity only. Underneath, the
wwstage post-order revisit re-stamped the constant-folded enum
member (an N_INTLIT) as untyped_int, clobbering the enum stamp the
N_DOT fold applied, so the widen matcher fell to its first-variant
fallback -- the #59.9 N_BIN guard now twins on N_INTLIT (cstage
cexpr is single-pass and never clobbered).
Two silent seams in one sweep. The for-range destructure silently
dropped the 9th+ binding in both stages (bind arrays are sized 8);
the cap now hard-stops per the DEFER_MAX/LOOP_MAX discipline (the
shape is unreachable today -- every wide-tuple construction path
already loud-stops). argtaggedwidensz, the drain-side SSoT for
widened call args, still keyed "natural push" on slot-size equality
while pushargsrev flipped to type equality with #55 -- a same-slot
subset was classified widen by push, natural by drain (counts
coincide today; a classification reader desyncs, the #48 shape).
Both sides now share the wsame key; the widen-branch tag miss for a
concrete source joins the task-2 loud-stop family (tagged subset
sources keep t=0 -- their widentag is never read, the scratch store
remaps).
Lead 17 (enum fold-failure prev+1) DISPROVED: enumvalfold gates
every member init in the checker and its fold set is op-for-op
equal to cgen's enumevalmember, so the fallback only runs inside
already-failing compiles.
cgstructlitfill's `...` total read only an N_INTLIT dim node, so a
def-dimensioned [N]T struct field under-filled: elements 1..N-1 kept
the zero-fill, silently, wwstage only (cstage and the tn twin read
the stamped array length). Read tichase(fi.tnode.type_).alen first;
the surface node stays as the fallback for unstamped shapes.
Hare's rule (harec check.c binarithm): % and the bitwise/shift five
are integer-only; + - * / need numeric operands. ww grouped % with
the numeric ops, and compound assigns never op-checked at all, so
`a % b` on floats compiled half-lowered (live cs!=ww divergence),
`a %= 2.0` plain-stored the rhs (op silently dropped, both stages),
and `s += "cd"` garbled str headers. Gate both at the checker, both
stages; the cgen float-compound fallbacks and the three unknown-
compound legacy defaults (deref/global/local) demote to rule-7 hard
stops. 34 compound-on-tagged/str/slice fixtures re-pin from the old
cgen "not wired" stops to the earlier checker diagnostics; 3 new
reject fixtures pin the closed shapes.
The chained value-struct walker's N_CALL arm handled only <=24B
register returns; an sret-class rhs fell to the scalar tail and
stored ONE word (the sret dest pointer) into the leaf -- silent
truncation in BOTH stages, byteid-blind. Point the callee's hidden
RDI at the BP-relative leaf slot (the single-dot #234 arm verbatim);
a ptr-root/global chain joins the #234-tail loud-stop family.
Every section banner dies (103 -> 0) across test/lang, the observer
suites, the C carriers, and the five comment-heavy corpus fixtures;
banner provenance (#N cites, carrier numbers, repair-cluster labels)
folded into headers or adjacent WHY comments. Narration deleted; row
provenance, ref cites, divergence pins, and layout contracts kept
(fwd-ref decl-order guards and bootstrap-gate corpus rationale
restored where the sweep over-cut). Comment-only proven: all 3742
wwbuild workdir .s byte-identical before/after; test-commit and
test-byteid (161 lang + 1399 data, 0 pinned-divergent) green.
Go compiles only _test.go files as tests; discovery now keys on the
_test.ww suffix alone. The line-leading-@test compatibility allowance
(noncanonical filenames admitted as test sources) is removed from both
driver stages and the coordinator. An @test declaration outside a
*_test.ww file is rejected loudly ("@test declaration outside
*_test.ww", wording byte-identical cs/ww) instead of silently running
under compose or silently dropping in a non-T build (#6). Tree audit
found zero real carriers; the two allowance fixtures flip canonical
(dep_test.ww, widget_test.ww). New pins: direnum attest-noncanon
reject row (both-stage stderr parity) and the coordinator
noncanonical_attest_rejected package row.
lib/strconv/test/ was the last _test layout deviating from Go's
in-package shape (src/bytes/bytes_test.go declares bytes_test in the
package dir). Its rationale — `import strconv` file-hitting the
sibling strconv.ww — dissolved when #98 made directory packages win
over same-named files on any search entry. libbyteid re-paths the
three fx entries and drops the covered() carve-out: the completeness
scan now keys lib/strconv through the fixtures' dirname. Walk line
flips to "ok lib/strconv [strconv_test, external]".
Unblocked by the package-mode ruling: same-package test files now
compose everywhere (coordinator dir-mode owns test-library and the
libbyteid dir entry owns byte identity), so the per-file standalone
constraint is gone and Go's stdlib layout applies directly. The
15-banner strings_test.ww monolith dissolves into per-ref-file
family files — dup, concat, trim, sub, utf8, iter, tokenize
(tokenize+splitn+cut, all of ref tokenize.ha), pad, replace — plus
helpers_test.ww holding exactly the one cross-family helper (streq),
Go's shared test-helper idiom. Pure moves; family-local helpers
(expect_str_token et al.) stay in their family file. Leading banners
that merely restated the filename dropped; 6 interior sub-family
boundaries remain. lib/ census 141 -> 132.
libbyteid gains the dx() dir-mode entry form decided in B2: compose
every *_test.ww under moddir exactly as pkgcombined does
(module-reset separators, byte-lex order) and byte-id the composed
root through both driver stages. The five per-file strings fx
entries retire into one dx("lib/strings") — every source line they
covered is inside the composed unit, and the completeness scan still
keys the module. NENTEXPECT 60 -> 56.
Recorded, not split: fmt_test's 13 banners are scenario groups over
the one fprint surface and ref/hare/fmt itself keeps a single
+test.ha — a print/wrappers split would fight the ref; memio stays
per the standing ruling (everything ww ports lives in ref
stream.ha).
Go has no per-file test targets: the PACKAGE is the unit of testing
(`go test ./...`) and same-package test files compose together. The
59-target LIBRARY_TESTS fan-out (per-file -w workdirs, one Make rule
per suite) collapses to one line: `ww test -j $(JOBS) -w
out/wwbuild/wwtest-lib -I lib/ww lib/...` — the regex dir-route
precedent generalized. The lib/regex line and the per-file pattern
rule instance dissolve with it (test/lang keeps its own rule).
Measured before committing (-j4, strings edit row): old per-file
warm 4.7-4.9s; bare walk 5.2-5.6s — a real regression, so the
coordinator first gained the brief's persistent per-package workdir:
`-w DIR` on a package target forwards to wwpackage, which keys
DIR/<dir>_<pkg> per group and hands it to each inner `ww test -c`
build. Reuse stays entirely with the driver's existing
content-identity contract — the coordinator adds pure path policy,
no cache machinery. Both driver stages drop their package-target -w
rejects (forward instead); -w with -c stays rejected at the
coordinator (two ownership contracts). After: 3.9-4.0s on the edit
row, 1.0s warm no-op, 2.5s cold — faster than the old flow on every
row.
package_test's tree -w reject row becomes the positive contract
(cold+warm byte-stable stream, cs/ww same) plus the -c conflict
reject. libbyteid roster shape DECIDED: per-file fx entries stay —
every enrolled file is still standalone-buildable, so coverage is
byte-for-byte unchanged; the dir-mode entry form arrives only with
the B3 shared-helper split that first needs it. Docs: owner table,
target table, -w contract paragraph.
The bbdd8bed residue, ruled by the Go derivation (ww's for IS the Go
for; the cstage grammar is the language definition and already the
Go-shaped one):
- bare `for { }` accepted (align UP to parse.c:1023, incl. for-else);
- 3-clause cond and post each omissible — `for (init;; post)`,
`for (init; cond)`, `for (init;)` (align UP, parse.c:1092-1097);
- 2-clause `for (cond; post)` REJECTED (align DOWN): the form exists
in neither Go nor cstage (parse.c:1101 eats a stray ';' then
requires ')'), so the old wwstage accept was a parser bug. The
reject wording mirrors cstage's failure mode per stage.
forhdr_{brace,emptymid,partial} run fixtures pin the accepted forms
byte-identically; forhdr_twoclause_reject pins both reject fragments.
Corpus pin 1745/346/21/209/1169/3490.
A module-scope let whose rhs runs code (alloc, call — peeled through
cast/?/! wrappers) emitted no DATAW slot: emit_lets' fold-fail
silently skipped the definition and every reference died at LINK
time with 'undefined reference', the one unacceptable failure mode
(rule 7). Hare's model rejects at check time (ref/harec/src/
check.c:4360 'Unable to evaluate initializer at compile time') and
routes runtime init through @init, which ww does not have — so both
frontends now reject at the declaration with identical wording.
alias_infptr_global flips compile->error as the alloc pin (its
letvartnode N_TPTR-over-N_TSTRUCT coverage lives on in the local
alias_infptr_{nest,slicecap} siblings); callinit_global_reject pins
the call shape. Corpus pin 1741/345/21/209/1166/3482.
The two loud siblings filed in d3822d77: (a) an auto-deref *[N]T
indexed base (hs[k].result) failed cgplaceaddr's N_INDEX arm, which
knew only TY_SLICE/TY_ARRAY bases — add the one-pointer hop (the
(*hs)[k] form made implicit; load shape is the slice .ptr word's);
(b) a bare slice-element aggregate source (use(sl[k])) fell off
aggarg_srcaddr's ident-array-only N_INDEX arm into the #271 loud
stop — route the miss through the same cgplaceaddr fallback the
N_DOT arm uses. Both stages, byte-identical (probe matrix: let-copy,
field-assign, call-arg, return, indexed-store all IDENT).
After this, every ADDRESSABLE aggregate source resolves: ident
(local/module-let), deref, dot-chain, and index over array/slice/
ptr-array spines recurse through cgplaceaddr; the remaining loud
paths are rvalue sources (#40 family) and the #274 const-def arg,
both documented divergences. 8 rows added to idxdot_aggcopy_test.
pushargsrev's five aistagged gates (N_IDENT #55, N_CALL #21, N_INDEX
#12, N_DOT #22a, deref #35) treated a tagged arg as already-tagged
when its SLOT SIZE matched the param's. A same-slot subset union
((bool|void) into (i64|bool|void), both 16B) then natural-pushed the
narrower box's words carrying SOURCE tags — no re-layout, no
cg_widen_tag_remap twin — so the callee matched the wrong arm
(silent: probes exited 10/90 where cstage exits 30/27). cstage keys
widen detection on type equality (cgen.c:10000 same = (pu == au) ||
type_eq) and routes every non-same tagged source through the zeroed
scratch + tag remap; the slot-DIFFER wwstage path already mirrored
that byte-identically, so the fix computes cstage's same check once
(wsame) and replaces each slot-size test with it. This also erases
the last known cs!=ww shape divergence (the 16B-local staging vs
direct-push frame delta on prefix subsets).
8 subsetwiden_* fixtures own the class: call-result/ident/str-payload
/mid-arg remap (the wrong-arm shapes), prefix (the shape-divergence
repro), and bigslot/return-pos/struct-24-to-32 sibling guards. Corpus
pin 1740/343/22/209/1166/3480.
Pure move: log_test.ww dissolves along its banner seams into
funcs_test.ww (the six logger-arg rows — lprintlnbasic/single/empty,
lprintflnbasic/indexed/mods — plus the fatal-family subprocess TODO;
ref/hare/log/funcs.ha owns lprintln/lprintfln and the fatal/lfatal
forms) and global_test.ww (defaultwiredtoglobal, setloggerswap,
printflnglobal; ref/hare/log/global.ha owns default/global/setlogger).
Moved blocks are byte-identical; the 9 banner lines are deleted.
Imports minimized per file (log + memio; the stale fmt/io imports
drop).
Helper inventory: streq spans both halves (all six funcs rows;
setloggerswap + printflnglobal on the global side), so it is
duplicated under per-file names per the sanctioned strconv
streq/fstreq precedent — fstreq in funcs_test.ww (decl + 6 call
sites), gstreq in global_test.ww (decl + 6 call sites); bodies
byte-identical apart from the name. Line-multiset diff old-vs-concat
(heads/banners excluded, names normalized): the only residue is the
9-line streq helper counted twice.
Order-safety, proven on the composed run: dir-mode executes
declaration order per file, files byte-lexicographic (funcs_test <
global_test < silent_test). Observed order: lprintlnbasic,
lprintlnsingle, lprintlnempty, lprintflnbasic, lprintflnindexed,
lprintflnmods, defaultwiredtoglobal, setloggerswap, printflnglobal,
silentwritesnothing, silentignoresprintfln — defaultwiredtoglobal
still precedes every log.setlogger caller (setloggerswap and
printflnglobal, both later in its own file; funcs and silent rows
never call setlogger).
Consumers: Makefile LIBRARY_TESTS replaces the log_test.ww entry with
the two new entries in place; test/byteid/libbyteid_test.ww roster row
becomes two fx rows, NENTEXPECT 59->60.
Validation: standalone ww test lib/log/funcs_test.ww (6 passed) and
lib/log/global_test.ww (3 passed); dir mode ww test lib/log (11
passed, no duplicate symbols); byteid compile-only build exit 0, 60
roster appends == NENTEXPECT.
Pure move: bufio_test.ww dissolves along its banner seams into
stream_test.ww (13 stream* rows) and scanner_test.ww (13 scan*/
newscanner*/emptystream/errorsource/boundarycases/multifill/
readaheadcantgrow rows), mirroring ref/hare/bufio/{stream_test+test.ha,
scanner_test+test.ha} ownership. streamscannerunread stays stream-side:
Hare's stream-level unread test lives in stream_test+test.ha:86.
Moved blocks are byte-identical; the 28 file-scope banner lines (and
their // continuation lines) are deleted, the 2 interior banners inside
boundarycases stay. Imports minimized per file (the unused `import
bytes;` drops; utf8 is scanner-only).
Helper inventory: putstr spans both halves (7 scanner rows / 8 call
sites; 8 stream rows / 8 call sites), so it is duplicated under
per-file names per the sanctioned strconv streq/fstreq precedent —
scanner_test.ww keeps `putstr`, the stream copy is `sputstr` (decl,
head comment, 8 call sites; body otherwise byte-identical). The
error-returning source (errvt/errread/errwrite/errsource) moves with
its sole consumer errorsource into scanner_test.ww; the close-recording
source (srcclosed/closevt/closesink/closewrite/closeclose/closesource)
moves with streamclosenopropagate into stream_test.ww. Line-multiset
diff old-vs-concat (heads/banners excluded, sputstr normalized): the
only residue is the 10-line putstr helper counted twice.
Consumers: Makefile LIBRARY_TESTS replaces the bufio_test.ww entry with
the two new entries in place; test/byteid/libbyteid_test.ww roster row
becomes two fx rows, NENTEXPECT 58->59.
Validation: standalone ww test lib/bufio/scanner_test.ww (13 passed)
and lib/bufio/stream_test.ww (13 passed); dir mode ww test lib/bufio
(26 passed, no duplicate symbols); byteid compile-only build exit 0,
59 roster appends == NENTEXPECT.
taggedcallslot gated on an N_IDENT callee + fnretlookup, so every
N_DOT / wwi-decl'd cross-module callee (and every fn-pointer call)
returned 0 and its tagged call-result ARG fell off the cursor-push
path into a 16B scratch spill where cstage PUSHQes AX/DX (cstage keys
the same push on args[i]->type, cgen.c tagged_arg_size). Read the
stamped result type instead — the #209/#211 predicate-to-stamp
discipline, same class as the fn-value cgident fix.
Graduates BOTH remaining DATABYTEID_DIVERGED pins
(r700_strings_byteindex frame 80->64, r839_xmod_nominal_match frame
32->16) — the ledger is EMPTY; the byteid gate ran 1389 data fixtures
at 0 pinned-divergent. Lang rows cover the same-module control,
fn-pointer, float-member, and str-member shapes (byte-identical each).
Separate latent lead banked, NOT closed here: the tagged
subset-widening call arg ((i64|bool) passed as (i64|bool|void))
byte-diverges pre-existing — cstage stages through a 16B local,
wwstage passes direct; runtime-equivalent.
The last Open-driver-work bullet. `-c -o <name>` replaces the fixed
<package>.test stem for exactly one package; the coordinator rejects a
multi-package fan-out ("cannot use -o with multiple packages", Go's
`go test -o` rule) and -o without -c is rejected at the driver
("needs -c for a package target" — a plain run executes from the temp
root, so a caller-owned name has nothing to name). Both driver stages
byte-identical wording; -S keeps its single-file-only reject.
package_test gains the contract row (naming, fixed-stem absence,
artifact runs, both rejects, both drivers); the tree-mode -o row's
pinned wording follows the contract.
Pure move: utf8_test.ww dissolves along its banner seams into sibling
rune_test.ww (runesz/utf8sz), encode_test.ww (encoderune),
decode_test.ww (decoder next/prev/validate/remaining/slice/position
plus the encode->decode round-trip), and types_test.ww (strerror),
mirroring ref/hare/encoding/utf8/{rune,encode,decode,types}.ha
ownership (types.ha:12 owns strerror). Blocks are byte-identical;
only the banner lines are deleted. The streq helper moves with its
sole consumer, strerror_cases, into types_test.ww. The impl utf8.ww
is untouched (no banners).
Consumers: Makefile LIBRARY_TESTS replaces the utf8_test.ww entry
with the four new entries at the same position; the
test/byteid/libbyteid_test.ww roster row becomes four fx rows,
NENTEXPECT 52->55 (+3).
Pure move: bytes_test.ww dissolves along its banner seams into sibling
equal_test.ww, index_test.ww (u8 + []u8 arms of index/rindex),
contains_test.ww (contains/hasprefix/hassuffix), tokenize_test.ww
(tokenize/rtokenize/peektoken/remainingtokens + splitn/rsplitn/split +
cut/rcut), and trim_test.ww, mirroring ref/hare/bytes/{equal,index,
contains,tokenize,trim}.ha ownership (Hare keeps splitn and cut in
tokenize.ha; contains.ha owns hasprefix/hassuffix). Blocks are
byte-identical; only the banner lines are deleted. Helpers stay with
their sole consumers: expect_token/expect_done/expect_tok in
tokenize_test.ww, beq in trim_test.ww.
Consumers: Makefile LIBRARY_TESTS replaces the bytes_test.ww entry
with the five new entries at the same position; the
test/byteid/libbyteid_test.ww roster row becomes five fx rows,
NENTEXPECT 48->52 (+4).
Pure move: the hasprefix/hassuffix, contains, byteindex/rbyteindex/
index/rindex, and compare sections of strings_test.ww become sibling
suffix_test.ww, contains_test.ww, index_test.ww, compare_test.ww,
mirroring ref/hare/strings/{suffix,contains,index,compare}.ha
ownership. Blocks are byte-identical; only the section banner lines
are deleted (the file names now carry them).
The remaining families (dup, concat, trim, sub, utf8, iter, tokenize,
pad, replace, cut) stay in strings_test.ww: they all consume the
file-local streq helper, and a helper cannot be shared across split
test files — a single-file test root does not pull same-package
siblings (undefined: helper), while dir-mode composes all package
test files into one unit (duplicate fn helper). Splitting them would
force either helper duplication or renames, both out of scope for a
pure move.
Consumers: Makefile LIBRARY_TESTS gains the four new entries beside
the strings_test.ww row; test/byteid/libbyteid_test.ww roster gains
four fx rows, NENTEXPECT 44->48 (+4).
Mirror ref/hare/time's impl layout in the test siblings: constants ->
duration_test.ww (ref/hare/time/duration.ha:9-18 owns the constants);
now/sleep rows -> instant_test.ww (instant is the subject type,
ref/hare/time/instant.ha; now/sleep bodies live in
ref/hare/time/+linux/functions.ha, a platform split ww does not have);
add/diff/compare rows -> arithm_test.ww (ref/hare/time/arithm.ha).
Pure move: every @test block is byte-identical; only the section
banner lines are deleted (the file names now carry them). The stale
file header naming the retired `ww run lib/time/timetest.ww` entry
point is dropped, not relocated (rule 8: it described a WHAT that no
longer exists).
Consumers: Makefile LIBRARY_TESTS entry replaced in place;
test/byteid roster 44->46 (+2).
Pure file-boundary move: the two silent-logger rows
(silentwritesnothing, silentignoresprintfln) leave lib/log/log_test.ww
for lib/log/silent_test.ww, mirroring ref/hare/log/silent.ha's
ownership (ref/hare/log has no test files of its own; the file name
follows the impl layout as directed). Only the two banner lines are
deleted; both moved blocks are byte-identical. silent_test.ww imports
log + memio only (neither row uses streq/fmt/io).
The specced funcs_test/global_test halves stay merged in log_test.ww:
the streq helper is consumed by six lprint* rows AND the
setloggerswap/printflnglobal global rows, and same-package test files
compile as one unit in dir mode (duplicate fn rejected), so that
boundary cannot be a pure move; reported upstream rather than
relocating the majority of rows.
Ordering: defaultwiredtoglobal must precede any log.setlogger caller.
All setlogger callers (setloggerswap, printflnglobal) remain after it
in log_test.ww; the silent rows never touch setlogger, and dir-mode
concat order (pkgsort: log_test.ww < silent_test.ww) keeps
defaultwiredtoglobal first overall.
Consumers: Makefile LIBRARY_TESTS gains lib/log/silent_test.ww beside
the log_test.ww entry; test/byteid/libbyteid_test.ww roster gains
fx("lib/log/silent_test.ww") after the log_test row, roster 44->45
(+1, NENTEXPECT bumped).
Validation: standalone ww test lib/log/log_test.ww (9 passed) and
lib/log/silent_test.ww (2 passed); dir mode ww test lib/log (11
passed, defaultwiredtoglobal first); test/byteid/libbyteid_test.ww
compile-only build exit 0, 45 roster appends == NENTEXPECT.
`case T1 | T2 =>` (binding-less; cstage parse.c:635-650 chains extra
types through cs->list, bindings stay single-type by design). Three
wwstage layers, no AST change (node.list already exists):
- parser (expr.ww): pipe loop after the non-let arm's first
parsetype;
- checker (check.ww): resolvewalk N_MCASE now walks n.list so each
alt gets its type_ stamp (exhaustiveness/casecovers were already
alt-aware, built ahead of the parser);
- cgen (cgenexpr.ww): the single-pattern want-computation moves
VERBATIM into matcharmwant; a cs.list arm emits CMPQ/JE per alt
funneling into one match_body label, mirroring cgen.c:11118-11141
incl. label mint order and the tag<0 clamp. Nullable arms keep
ignoring alts (both stages).
Graduates the held e2e row (pin 1732/1158/3464); byte-identical on
the repro and the single-pattern control.
cstage parse.c:1027 accepts `for ()` — N_FOR with a nil cond, no
for-else arm, no test emitted (an unconditional loop; a deliberate
Go-flavored ww divergence from Hare, original to the toolchain
import). The wwstage parser had no RPAREN early-out and rejected it.
Selfhost checker and cgen already nil-guard n.cond, so the parser arm
is the whole gap. Graduates the held e2e row (pin 1731/1157/3462).
Adjacent asymmetries left filed, not fixed here (rule 11): the brace
form `for { }`, the empty middle clause of the 3-clause form, and
the REVERSE case (wwstage accepts 2-clause `for (cond; post)` which
cstage rejects).
wwstage dotchainresolve gated its *T roots on an N_TPTR-over-N_TNAME
tnode; an inferred `let p = alloc(S{...})!` rides the checker-
SYNTHESIZED N_TPTR whose pointee is the struct BODY node (the #24
TNAME-normalize covers only the direct struct-lit binding), so the
root gate failed and chained p.field.pseudo reads fell to the
unfused deref arms — shape-only divergence vs cstage's type-keyed
fold (both stages runtime-correct; the historical field(SB) leak the
pin described was already fixed). Widen the local and global root
gates to accept the N_TSTRUCT pointee; correctness stays enforced by
the stamped-tinfo peel below (TY_PTR -> pointee TY_STRUCT).
Graduates alias_g73_heapfill out of DATABYTEID_DIVERGED (2 pins
remain, both the tagged-spill family); adds compile fixtures pinning
the newly-converged siblings (nested read+store, slice .cap,
inferred-global root; pin 1730/22/3460) and a runtime lang row that
mutates then re-points the heap base — a read bypassing the pointer
returns the wrong len.
The last bug-pinned C carrier. Its header documents both #55 halves;
with the cgen side fixed the STRONGER assertion set it deferred is
expressible: barevalue builds the 794 two-file program FLAT
(file-keyed import — a dir-keyed aa/ compiles aa as its own sep unit
where main.v is invisible and the collision cannot express), runs
exit 7 on BOTH drivers, and asserts the flat __root.s cs==ww
byte-identical (rule 10). defshadow pins the def-vs-fn arm-order
corner (foreign scalar def under a curmod fn: bare read 42, not
141), modqualfnval the qualified fn-value positive twin.
Carrier fleet 16 -> 15: 5 units / 6 bootstrap / 3 platform /
738_module_decl. Zero bug-pins remain.