Files
ww/test
Hojun-Cho 069548d424 cstage+test: graduate hidden-name mklabel sites to @-prefix SSoT (#26)
Class A frame-layout landmine pre-located; #26c queued for size-
strategy convergence per rule 10.

Cstage's tagged-scratch sites previously stamped per-call labels
via mklabel "tagbase"/"tagscr"/"argscr"/"idxscr", bumping labelseq
once per call and allocating a fresh frame slot. Wwstage routes
the same sites through localadd("@tagbase", ...) and
localadd("@tagscr", c.tagscrsz, nil) — the @-dedup shares ONE
slot per name per fn and never touches labelseq. @tagscr is
shared across THREE wwstage sites: cgenutil.ww:180 pushargsrev
struct-payload widen, cgenutil.ww:2918 cgwidentaggedstore
via_outer, cgenexpr.ww:3524 cgindex tagged-element. Worker's
initial draft introduced cg_argscr / cg_idxscr as separate
cache vars — names that don't exist in wwstage. Per rob's rule-10
amendment those collapsed to a single cg_tagscr shared across
the 3 sites, matching wwstage's @tagscr SSoT exactly.

Cstage now caches two slots matching wwstage's namespace exactly:
cg_tagbase (8B base spill, 1 site at cgwidentaggedstore via_outer)
and cg_tagscr (sized scratch shared across the 3 sites above).
Eliminates per-call labelseq bumps and per-call frame churn.
Class A byte-id drift (silent corpus-coverage-blind landmine)
closed for the 1-name shape match. Model: STATUS-3 #15 commit
987391b routed @retscr through the same SSoT via cg_retscr;
this commit extends the carve-out to @tagbase and @tagscr.

Size strategy: cstage has no scanlocals pre-pass (wwstage's
c.tagscrsz pre-pass at cgendecl.ww:32 tagscrbump computes the
per-fn max). First call across the 3 @tagscr sites sizes the
slot; subsequent calls reuse if sz <= cached, fatal() if larger
(rule 7: surface-don't-silently-corrupt). Long-term rule-10
convergence — wwstage DOWN from scanlocals to first-use+fail-loud
on BOTH stages (per rob: aligning richer DOWN to leaner) — is
filed as #26c, separate concern from #26's name-SSoT graduation.

Tests:
  - 736_cstage_label_ssot succ_rows: pins cstage-vs-wwstage cmp -s
    byte-id on the canonical pointer-rooted two-tagged-store shape
    (two `c.v = (...: bag);` writes through *cell). Pre-fix cstage
    frame was 16B+48B larger (2*@tagbase + 2*@tagscr per call);
    post-fix single-slot SSoT matches wwstage byte-for-byte.
  - 736_cstage_label_ssot fail_rows: pre-locates the size-grow
    landmine. A fn with two unions of different slot sizes (16B
    then 24B) routed through @tagscr; cstage must fatal() with
    "@tagscr cached sz" + size mismatch + #26c follow-up cite.
    Gates corpus growth into this shape against silent miscompile.

110/110 ok. 995_self_rebuild byte-id holds (ww2 == ww3 == ww4).
2026-05-18 16:00:31 +09:00
..