make: add test-lang-byteid T2 cross-stage .s byte-id gate

Compiles every test/lang/*_test.ww twice through the same cstage ww
orchestrator swapping only the frontend (WW_W6C = w6c vs w6c_ww) and
asserts every per-package <pkg>.s (incl the synth-main __root.s) is
byte-identical. This is the rule-10 stage-symmetry gate test/runww.ww
reserves as T2. .s-only (Q3); .o/.wwi are 991/992's surface. Distinct
WW_PKGCACHE per leg, both caches+sepworks wiped per file. Recipe is
parameterized over an input-class (file-list + build-verb); only the
test/lang class ships now, fold-6 slots in build --sep for selfhost/data.
Wired into make test (pre-push) only, not test-commit/test-unit.
This commit is contained in:
2026-06-22 07:56:20 +09:00
parent e1740fff10
commit f56b056ed3

View File

@@ -3659,7 +3659,7 @@ sizelint:
peellint:
@sh tools/peellint
test: all sizelint peellint $(TESTS)
test: all sizelint peellint $(TESTS) test-lang-byteid
@WW=$(BIN)/ww BIN=$(BIN) sh test/run
test-unit: all sizelint peellint $(TESTS)
@@ -3686,6 +3686,67 @@ test-lang: all
echo "ww test $$f"; $(BIN)/ww test $$f; \
done; echo "test-lang: all ok"
# ---- test-lang-byteid: T2 cross-stage .s byte-id gate (fold 4) ---------
# For every test/lang/*_test.ww, compiles it TWICE through the SAME cstage
# `ww` orchestrator swapping ONLY the frontend (WW_W6C = w6c vs w6c_ww) and
# asserts every per-package <pkg>.s (incl the synth-main __root.s) is
# byte-identical cs-vs-ww. This is the rule-10 stage-symmetry gate that
# test/runww.ww:9-15 reserves ("T2"); strictly more sensitive than re-running
# behavior. .s-ONLY by design: .o/.wwi are the assembler's surface (gated by
# 991/992) — diffing them here would false-attribute an assembler bug to cgen.
# WW_W6A/WW_W6L are pinned to the NON-_ww binaries on BOTH legs: the .s is the
# frontend's product (the assembler runs after), so the SOLE variable is
# WW_W6C. Distinct WW_PKGCACHE per leg is mandatory — a shared cache lets the
# ww leg HIT the cs-built package and never run w6c_ww (false GREEN). Depends
# on `all` so both frontends are at HEAD (stale-binary is the #1 false-pass).
# Pre-push (`make test`) ONLY — never test-commit/test-unit (byte-id is being
# demoted to pre-push; a content-keyed T2 would defeat that demotion).
#
# The recipe is parameterized over an input-class = (file-list, build-verb);
# only the test/lang class ships now. SEAM for fold-6: add a second class
# (`ww build --sep` over selfhost/data) plus //ww:error reject-routing (assert
# both legs fail) — no reject cases exist in test/lang today.
LANGBYTEID_DIR = $(OUT)/langbyteid
LANGBYTEID_FILES = $(wildcard test/lang/*_test.ww)
LANGBYTEID_VERB = test -c
LANGBYTEID_EXPECTED_MIN = 16
$(if $(LANGBYTEID_FILES),,$(error test-lang-byteid: empty corpus))
test-lang-byteid: all
@set -e; \
mkdir -p $(LANGBYTEID_DIR); \
n=0; \
for f in $(LANGBYTEID_FILES); do \
base=$(LANGBYTEID_DIR)/`basename $$f .ww`; \
rm -rf $$base.cs.sepwork $$base.ww.sepwork $$base.cs.cache $$base.ww.cache; \
WW_W6C=$(BIN)/w6c WW_W6A=$(BIN)/w6a WW_W6L=$(BIN)/w6l \
WW_PKGCACHE=$$base.cs.cache \
$(BIN)/ww $(LANGBYTEID_VERB) -o $$base.cs $$f; \
WW_W6C=$(BIN)/w6c_ww WW_W6A=$(BIN)/w6a WW_W6L=$(BIN)/w6l \
WW_PKGCACHE=$$base.ww.cache \
$(BIN)/ww $(LANGBYTEID_VERB) -o $$base.ww $$f; \
cs_set=`cd $$base.cs.sepwork && ls *.s | sort`; \
ww_set=`cd $$base.ww.sepwork && ls *.s | sort`; \
if [ "$$cs_set" != "$$ww_set" ]; then \
echo "test-lang-byteid: FAIL $$f: .s set differs cs-vs-ww"; \
echo " cs: $$cs_set"; echo " ww: $$ww_set"; exit 1; \
fi; \
echo "$$cs_set" | grep -qx __root.s || { \
echo "test-lang-byteid: FAIL $$f: no __root.s emitted"; exit 1; }; \
ns=0; \
for s in $$cs_set; do \
cmp -s $$base.cs.sepwork/$$s $$base.ww.sepwork/$$s || { \
echo "test-lang-byteid: FAIL $$f: $$s differs cs-vs-ww (rule-10)"; \
exit 1; }; \
ns=`expr $$ns + 1`; \
done; \
test $$ns -ge 1 || { echo "test-lang-byteid: FAIL $$f: 0 .s compared"; exit 1; }; \
echo "ww test-byteid $$f ($$ns .s cs==ww)"; \
n=`expr $$n + 1`; \
done; \
test $$n -ge $(LANGBYTEID_EXPECTED_MIN) || { \
echo "test-lang-byteid: corpus shrank ($$n < $(LANGBYTEID_EXPECTED_MIN))"; exit 1; }; \
echo "test-lang-byteid: $$n files cs==ww"
# ---- test-commit: per-commit default (task #10 T1) ---------------------
# Full suite, but content-key-SKIPS the expensive wwstage byte-id /
# self-compile gates (950/989_lib_byteid/990-997) when their input set is
@@ -3876,4 +3937,4 @@ nocc:
@echo
@echo "NOCC OK: $(STAGE0)/* reproduces itself from source. cc not invoked."
.PHONY: all cstage wwstage test test-unit test-commit test-run test-lang smoke sizelint peellint install clean bootstrap nocc bootstrap-snapshot
.PHONY: all cstage wwstage test test-unit test-commit test-run test-lang test-lang-byteid smoke sizelint peellint install clean bootstrap nocc bootstrap-snapshot