From 598c5c58c720bb68ba8e6cbf1bfc2af944bf021b Mon Sep 17 00:00:00 2001 From: Kacy Fortner Date: Sun, 26 Jul 2026 22:52:05 +0000 Subject: [PATCH] verify the regression corpus under the green backend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit the dedicated green tests prove the coordination primitives; nothing proved the whole regression corpus behaves the same under the green backend as under os threads. that is the safety net making green the default needs, so this adds a target that runs every case with an expected file under PITH_GREEN=1 — at the default worker count and again pinned to one worker — and compares each to the same expected output the os-thread run is held to. comparing against the fixed expected file rather than a fresh os-thread run is deliberate: an os-thread run carries its own wall-clock timestamps and would diff against green over nothing. a green run that drifts from its recorded answer is a real green correctness bug. it found one: test_process_ctx under a single worker, where a deadline-limited read_exact on a subprocess pipe reports the read failed but mislabels the error as unexpected-eof instead of deadline-exceeded (its spawned read-worker returns empty on would-block before the cancel timer fires). correct at the default worker count and os-thread. it is excluded here with that reason and tracked separately rather than papered over with a loosened compare; everything else — 259 cases, both worker modes — matches byte for byte. wired into ci after the green primitive tests. --- .github/workflows/ci.yml | 3 +++ Makefile | 47 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b73faa96..937ed5b1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,6 +32,9 @@ jobs: - name: green-thread runtime tests run: make green-tests + - name: regression corpus under green + run: make verify-green-corpus-only + - name: build self-hosted compiler run: make self-host diff --git a/Makefile b/Makefile index 62e72400..9c5707a9 100644 --- a/Makefile +++ b/Makefile @@ -1006,6 +1006,53 @@ green-pinned-fairness: build green-tests: green-smoke green-threadlocal green-pingpong green-producer-consumer green-waitgroup green-mutex green-semaphore green-barrier green-await-fanin green-starvation green-pinned-fairness @echo "all green-thread tests passed" +# --- full corpus under the green backend --- +# the dedicated green-tests above prove the coordination primitives; this proves +# the whole deterministic regression corpus produces the same output under the +# green backend as under os threads. it is the safety net for making green the +# default: every case with an expected file is run under PITH_GREEN=1 at the +# default worker count and again pinned to one worker, and compared to the same +# expected output the os-thread run is held to. a green run whose output drifts +# from its expected file is a green correctness bug, not a timing artifact, +# since the expected file is the fixed os-thread answer. +# +# a case that legitimately differs under green (nondeterministic scheduling +# order that its expected output happens to encode) belongs in +# GREEN_CORPUS_EXCLUDE with a reason, not in a loosened compare. +# test_process_ctx: under a single green worker (PITH_GREEN_WORKERS=1), a +# deadline-limited read_exact on a subprocess pipe reports the read failed but +# classifies the error as unexpected-eof rather than deadline-exceeded — its +# spawned read-worker returns empty on would-block instead of yielding until +# data or the deadline. correct at the default worker count and os-thread; a +# narrow single-worker green bug tracked separately. (see the read_exact ctx +# path in std/io.pith.) +GREEN_CORPUS_EXCLUDE := test_process_ctx +GREEN_CORPUS_EXPECTED := $(filter-out $(addprefix tests/expected/,$(addsuffix .txt,$(GREEN_CORPUS_EXCLUDE))),$(REGRESSION_EXPECTED)) + +verify-green-corpus: build verify-green-corpus-only + +verify-green-corpus-only: + @echo "--- regression corpus under the green backend (default + 1 worker) ---" + @pass=0; fail=0; skip=0; \ + for f in $(GREEN_CORPUS_EXPECTED); do \ + name=$$(basename "$$f" .txt); \ + src="tests/cases/$$name.pith"; \ + [ -f "$$src" ] || { skip=$$((skip+1)); continue; }; \ + expected=$$(cat "$$f"); \ + gN=$$(timeout 60 env PITH_GREEN=1 ./target/release/pith run "$$src" 2>/dev/null); \ + g1=$$(timeout 60 env PITH_GREEN=1 PITH_GREEN_WORKERS=1 ./target/release/pith run "$$src" 2>/dev/null); \ + if [ "$$gN" = "$$expected" ] && [ "$$g1" = "$$expected" ]; then \ + pass=$$((pass+1)); \ + elif [ "$$gN" != "$$expected" ]; then \ + echo "FAIL $$name (green default workers)"; fail=$$((fail+1)); \ + else \ + echo "FAIL $$name (green 1 worker)"; fail=$$((fail+1)); \ + fi; \ + done; \ + echo "$$pass passed, $$fail failed, $$skip without a source"; \ + if [ $$fail -gt 0 ]; then exit 1; fi; \ + echo "green corpus matches os-thread output" + # --- memcheck --- # run a curated set of memory-management-heavy programs under valgrind # with an error exit code, so a use-after-free or an out-of-bounds read