Repository navigation
codegen-corpus: compile sample moves with the run, so one commit is red and green (#851 W15) #885
Description
codegen-corpus goes red for a reason the commit does not decide
Part of #851, weak point W15: a gate that fails or passes for a reason other than its claim.
What was measured
The red is always the same. I read the logs of the nine Codegen Validation failures from 09-24 to 10-04, on every ref: 5 on main and 4 on PR branches. All nine print the same two lines:
DOES NOT COMPILE: specs/tri/phi_utils_multi.tri (ast-check passed it)
0 spec(s) regressed, 1 of 24 sampled outputs do not compile.
| run | created (UTC) | event | ref | SHA |
|---|---|---|---|---|
| 36011281829 | 09-24 14:13 | pull_request | trinet-fleet-truth | 4e13a68 |
| 36027587352 | 09-24 16:28 | push | main | 9eae0b4 |
| 36029076209 | 09-24 16:41 | push | main | 9947512 |
| 37016445887 | 10-02 13:56 | push | main | 4d2a864 |
| 37063193586 | 10-02 20:51 | pull_request | deps/docusaurus-3.10.2 | d104319 |
| 37065544442 | 10-02 21:13 | pull_request | ci/gates-floor-10 | 9a62c10 |
| 37088537159 | 10-03 02:05 | push | main | e6eac09 |
| 37102745385 | 10-03 06:20 | pull_request | ci/run-syntax-self-hosted | 57c3c56 |
| 37225448222 | 10-04 18:42 | push | main | 57de4a1 |
One commit, both verdicts. On e6eac0900, push run 37088537159 is red and schedule run 37090643092 is green. Main 57de4a1f5 is red on push (37225448222), while PR runs on the same spec tree are green.
The output really does not compile. Its compile errors, from the probe run below:
compute_phi_power(n: u32) PhiResulthas a stub body that falls off the end;- the generated test calls
encode_to_trits(allocator, "test"), but the function takes one parameter.
That is a generator defect and is tracked separately. The question here is why it is only sometimes sampled.
Why the sample moves
tools/codegen_corpus.zig compiles 24 outputs: every stride-th entry of this run's clean list, with stride = clean.len / 24.
- Green runs report 788 clean, so
stride = 32. The picks are indices 0, 32, …, 736. phi_utils_multiis baseline line 448, which is index 447. The slot at 448 is one past it.- If one spec that sorts before it counts as clean when the baseline does not hold it,
phi_utils_multimoves to index 448 and is sampled. 0 spec(s) regressedmeans every baseline entry was still clean, so the red runs had at least 788 clean.- Inference, not measured: the red runs had 789–791 clean, with exactly one extra entry before
phi_utils_multi. The tool never prints its clean count on the failure path, so the red runs did not record it.
A false clean that this can come from (measured locally):
vibee_genprintsBehaviors: Nbefore it generates.- When it cannot create or write the file, or when it produced 0 bytes, it leaves no file and exits 0 (
writeGenerated(...) catch return). zig ast-checkon a missing file printserror: unable to open file '…' for ast-check: FileNotFoundand exits 1. On a directory it printserror: unable to load file … ReadFailed, also exit 1.- Neither message contains
: error:, which is the only thingastCheckOklooks for. The exit code is ignored, so the spec counts as clean. - Measured later (probe 37242067946): a second hole. 18 baseline specs abort with SIGABRT after creating the output file and leave it empty, and
zig ast-checkpasses an empty file with exit 0. The abort is vibee_gen aborts (SIGABRT) on 18 Verilog specs and intermittently on 2 Zig specs #887.
What does not explain it:
- Probe run 37241431527 generated all 1137 specs 5 times on one runner, which took 104.9 s.
- 0 specs differ in exit code, behaviour count or output sha256.
- Clean equals the baseline (788), with 0 extra and 0 lost.
- Five repeats have little power against a rare flip, so this is not evidence that the generator is deterministic across runners.
- Same image
ubuntu-24.04 20260927.320.1on both runs of e6eac09. The red run was in westus2, the green one in westus. - No randomness or clock use in the generator path: I grepped
vibee_gen.zig,zig_codegen.zig,vibee_parser.zigandlang_generators.zig. vibee_genis built for the native CPU (standardTargetOptions). A CPU-dependent outcome is possible and not tested.
Side defect found on the way
The output name flattened / to _, so specs/storm/main.tri and specs/storm_main.tri both wrote .zig-cache/codegen-corpus/specs_storm_main.tri.zig. Neither spec is in the baseline, so this is not the cause, but the compile sample could have tested one spec's output under the other's name.
Fix (PR to follow)
- The sample is drawn from the committed baseline: slot k is baseline entry
k * stride. A run cannot move it. - A spec counts as clean only if the generator exits 0, leaves a non-empty regular file, and
zig ast-checkexits 0 with no: error:. - The output file is deleted before each generation. Its path mirrors the spec path.
- The clean count, regressed, new-clean and no-output specs are printed on both paths, by name. The next disagreement will then name its spec.
- The runner's CPU model is printed.
Done when
-
PR merged and its own
Codegen Validationrun is green. -
CI A/B on throwaway branches (main 37243529377, fixed 37243526975; all three rows below came out as expected). Each arm runs main's tool and the fixed tool on the same tree:
- plain;
- one extra clean spec added before
phi_utils_multi; - one non-baseline spec before it forced to leave no file;
- one baseline spec forced to leave no file.
Expected:
arm main's tool fixed tool extra clean spec red on phi_utils_multigreen, naming the new clean spec non-baseline spec leaves no file red on phi_utils_multigreen, naming the spec with no output baseline spec leaves no file green over the missing output red, naming the regression -
A separate issue for the
phi_utils_multigenerator defects. They are listed in vibee_gen aborts (SIGABRT) on 18 Verilog specs and intermittently on 2 Zig specs #887 under "Also found", which is not yet an issue of their own.
Not measured
- The clean count of any red run. It was never printed.
- Whether the generator's output differs between CPU models.
How many of the 788 baseline outputs compile.Measured in probe 37242067946: 19 never wrote a usable file (18 empty after SIGABRT, 1 missing; vibee_gen aborts (SIGABRT) on 18 Verilog specs and intermittently on 2 Zig specs #887), and 13 of the remaining 769 failzig test. fix(codegen): sample the corpus compile check from the baseline #886 re-records the baseline as 769.
Also seen, not this issue
src/firebird/vsa_simd.zig:448, test "benchmark dot product speedup", asserts a wall-clock ratio > 0.5; its siblings use > 0.1. It made the 09-29 scheduled run red (36515512024). src/firebird/ is outside the direct-edit zones, so the threshold is the owner's call.
🤖 Generated with Claude Code
Activity
fix(codegen): drop 19 baseline entries that never wrote a .zig (#885)
test(codegen): rerun the #885 A/B on #886's re-recorded baseline
test(codegen): same A/B helper as the fix arm, main's tool kept
fix(codegen): name the panic, not the last stack frame (#885)
fix(codegen): say "empty file" when it is one, and name crash-handler…
gHashTag commentedon Oct 4, 2026
Results: the A/B, the probe, and two corrections
A/B (
exp/corpus-ab-mainandexp/corpus-ab-fix, same helper and workflow, different tool; four arms on one runner each):specs/tri/a_s42_extra.tri) beforephi_utils_multiDOES NOT COMPILE: specs/tri/phi_utils_multi.triNEW CLEANnames itspecs/algo/avgpool2d.triblocked from writingspecs/algo/adam.tri(index 1, never sampled) blockedREGRESSED: specs/algo/adam.triMain's arms replicate the earlier run 37242996093. The shifted-sample mechanism in this issue is reproduced. So is its mirror image: a baseline spec that stops writing goes unnoticed by main's tool.
Probe 37242067946 (
exp/codegen-flake-ab): 60 passes over all 1033 specs with behaviours, removing the destination before each generation.language: varlogand leave a 0-byte file every time.specs/tri/long_context_system.vibeeleaves no file in 59 of 60 passes.zig ast-checkpasses an empty file with exit 0. So main's tool counted the 18 clean through the empty file, not a missing one.02b9958de, baseline 788 → 769).phi_utils_multimoves to index 432, which is still not sampled.specs/tri/hdc_stream_classifier.vibeeis not in the baseline and sorts beforephi_utils_multi. It aborts with no file in 3 of 60 passes. Main's tool counts that as clean, which is arm 3 above happening on its own.Correction 1: red-run count, in #886. #886's description said
mainwas red 9 times. The table above is right, but its 9 runs span every ref: 5 onmainand 4 on PR branches. Counted from the API (codegen.yml,branch=main, 09-24 to 10-04), branchmainalone was red 6 times:phi_utils_multiruns in the table;vsa_simdbenchmark, 36515512024, which is listed under "Also seen".#886's description now says so.
Correction 2: the cause of the false clean.
02b9958de's message said the 19 got into the baseline because ast-check ran on a missing output. That holds for one spec only; for the other 18 the file existed and was empty.d959eb722's message states the correction. The gate's ownNO OUTPUTline still saidno filefor all 19.b937408cemakes it sayempty filewhere that is what happened.#886's own CI. All three runs below report
769 of 1033 … clean, baseline 769, 0 regressed, 0 new clean, 19NO OUTPUT, and a clean compile sample.02b9958de(37243448031): everyNO OUTPUTreason was a symbol-less stack frame.d959eb722(37243963781): the 18 Verilog specs name the panic,programmer bug caused syscall error: FAULT. They are still labelledno file, andlong_context_systemstill shows a frame.b937408ce(37244594555): the 18 readsignal 6, empty file, … panic: programmer bug caused syscall error: FAULT.long_context_systemreadssignal 6, no file, Segmentation fault at address 0x7fee7103b2a2. Its abort is a segfault, not a panic; where it happens is not known (vibee_gen aborts (SIGABRT) on 18 Verilog specs and intermittently on 2 Zig specs #887).hdc_stream_classifierdid not abort in any of #886's 4 codegen runs, so the natural trigger above stays an inference.🤖 Generated with Claude Code
fix(codegen): say why a sampled spec does not compile, on top of the …
test(codegen): throwaway A/B for the corpus sample fix (#885)
test(codegen): rerun the #885 A/B on #886's re-recorded baseline
test(codegen): throwaway A/B for the corpus sample fix (#885)
test(codegen): same A/B helper as the fix arm, main's tool kept