Skip to content

Commit ae16b89

Browse files
committed
feat(tooling): D-553 — check_vm_parity becomes the non-default-backend e2e sweep
Smell-audited: 1: the first run immediately surfaced SIX tree_walk-only e2e failures (a SEGFAULT + two GC-related among them) that the vm-default gate never sees — filed as D-555 with per-step repros; the SKIPS list stays EMPTY until a failure is proven vm-default-specific (each entry requires a reason, no silent truncation). The idle corpus-only probe (D-196 era) now builds -Dbackend=tree_walk (the F-012 differential-oracle backend) and drives the corpus + the FULL test/e2e suite against it, on-demand / Phase-boundary cadence (ADR-0049). build.zig comments corrected: the enum-field spelling is tree_walk — `-Dbackend=tree-walk` (the old comment's spelling) is rejected by zig build. First-run result: corpus 3901/3901 green; 6 e2e fail -> D-555.
1 parent dde1550 commit ae16b89

3 files changed

Lines changed: 56 additions & 62 deletions

File tree

‎.dev/debt.yaml‎

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@
2424
# md-table-align no longer pads it to ~800 KB of whitespace.
2525

2626
active:
27+
- id: "D-555"
28+
status: "open (2026-07-06, found by D-553's first tree_walk full-e2e sweep — the repurposed check_vm_parity.sh doing exactly its job). SIX e2e steps FAIL on -Dbackend=tree_walk while green on the vm default (corpus 3901/3901 green on both): (1) phase15_watch_recursion — SEGFAULT (memory safety; HIGHEST priority); (2) phase16_gc_torture — dies (empty failure output; GC-related); (3) phase14_symbol_metadata sym_meta_gc_survives — got nil want 1 (symbol meta lost under GC — tree-walk rooting gap?); (4) phase14_seq_helpers2 interleave_large — got '' want 100000 (large-input crash/depth?); (5) phase15_dynamic_var guard — got 2 want 1; (6) phase15_require_fs missing — got 2 want 1 (exit-code shaped). The F-012 diff oracle (zig build test, both backends) is GREEN — these live in territory the oracle does not cover (GC trigger timing, deep recursion, watches, require-fs paths, e2e exit codes). Each is triage: a REAL tree-walk-backend bug (fix; the oracle backend must stay healthy) vs a vm-default assumption baked into the e2e (then SKIPS-list it in check_vm_parity.sh with the reason). Repro: bash scripts/check_vm_parity.sh (~8 min) or per-step: zig build -Dwasm -Doptimize=ReleaseSafe -Dbackend=tree_walk && CLJW_SKIP_BUILD=1 bash test/e2e/<step>.sh."
29+
category: "runtime"
30+
barrier: "none — deterministic repros in hand. Start with the phase15_watch_recursion SEGFAULT (memory safety) and the two GC-related fails (torture + symbol-meta) — likely a tree-walk-only rooting gap; the exit-code pair last (may be harness-shaped)."
31+
last_reviewed: "2026-07-06"
2732
- id: "D-554"
2833
status: "open (2026-07-06, split from D-239's discharge). The `(ns name {:attr-map} …)` ATTR-MAP and `(ns ^{:m 1} name)` name-symbol meta are still SKIPPED at analysis (special_forms.zig analyzeNs) — only the docstring lands as {:doc} ns meta. clj merges name-sym meta + attr-map + docstring into the ns meta. Rare vs the docstring (libs mostly use :author/:added attr-maps); needs a Form->Value map conversion at analysis + ADR-0169-style rooting OR an arena-thread of the literal into both backends (the doc rode NsFilterEntry as a plain string; a map needs a Value). Mechanise via phase15_ns_docstring e2e when landed."
2934
category: "clj-parity"
@@ -1332,19 +1337,6 @@ active:
13321337
barrier: |-
13331338
tractable now; M-sized survey-first. Value rises with D-528 (real deps.edn corpus).
13341339
last_reviewed: "2026-07-02"
1335-
- id: "D-553"
1336-
status: |-
1337-
open (2026-07-02, lifted from D-196's discharged tail — a follow-up living only
1338-
inside a discharged row is invisible to the active drain). Repurpose
1339-
scripts/check_vm_parity.sh to run the e2e suite on the NON-default backend
1340-
(tree_walk, the F-012 differential oracle) so an oracle-only e2e/rendering
1341-
regression cannot hide behind the vm-default gate. On-demand / Phase-boundary
1342-
cadence per ADR-0049 (never per-commit). The script's BLOCKERS list stays the
1343-
re-add point for future VM-only regressions.
1344-
category: "tooling"
1345-
barrier: |-
1346-
tractable now; S-M (swap -Dbackend + drive run_all's e2e list through it).
1347-
last_reviewed: "2026-07-02"
13481340
standing:
13491341
- id: "D-549"
13501342
status: |-
@@ -6528,6 +6520,12 @@ discharged:
65286520
barrier: "DISCHARGED (was: ns meta slot missing)."
65296521
last_reviewed: "2026-07-06"
65306522

6523+
- id: "D-553"
6524+
status: "DISCHARGED 2026-07-06 — check_vm_parity.sh repurposed to the NON-default-backend full-e2e sweep: builds -Dbackend=tree_walk (enum-field spelling; build.zig comments corrected from the misleading tree-walk) and drives the corpus + ALL test/e2e/*.sh against it, with an empirically-populated SKIPS list (currently EMPTY — the suite is backend-neutral so far) whose entries require a reason. On-demand / Phase-boundary cadence per ADR-0049 (never per-commit). The FIRST run immediately paid off: corpus 3901/3901 green but SIX e2e fail on tree_walk (a SEGFAULT + two GC-related among them) — filed as D-555. ORIGINAL: lifted from D-196's discharged tail; the idle corpus-only probe risked oracle-backend rot hiding behind the vm-default gate."
6525+
category: "tooling"
6526+
barrier: "DISCHARGED (was: repurpose the idle probe)."
6527+
last_reviewed: "2026-07-06"
6528+
65316529
conventions: |-
65326530
- Structure: two top-level lists — `active:` and `discharged:`. Active entries carry id / status / category / barrier (+ optional quality_floor / last_reviewed); discharged entries carry id / discharged_at / resolution. Edit as YAML (no Markdown table to align).
65336531
- New debt: grep `.dev/debt.yaml` for class-overlap before adding (per `.claude/rules/debt_dedup.md`).

‎build.zig‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,11 @@ pub fn build(b: *std.Build) void {
5151
// ROADMAP §9.6 / 4.8 / §349 — backend gate (ADR-0005 / ADR-0070 / F-012).
5252
// `vm` is the PRODUCTION DEFAULT (flipped 2026-06-02 once every D-196
5353
// parity blocker closed: check_vm_parity = 0 fails, corpus 375/375 + all
54-
// e2e green on vm). `tree-walk` is retained as the differential oracle /
55-
// reference implementation, selectable via `-Dbackend=tree-walk`.
54+
// e2e green on vm). `tree_walk` is retained as the differential oracle /
55+
// reference implementation, selectable via `-Dbackend=tree_walk` (the
56+
// enum FIELD spelling — `-Dbackend=tree-walk` is rejected by zig build).
5657
const Backend = enum { tree_walk, vm };
57-
const backend = b.option(Backend, "backend", "Evaluation backend (vm default — production; tree-walk = differential oracle)") orelse .vm;
58+
const backend = b.option(Backend, "backend", "Evaluation backend (vm default — production; tree_walk = differential oracle)") orelse .vm;
5859
build_options.addOption(Backend, "backend", backend);
5960

6061
// `-Dwasm` — the minimal polyglot Wasm FFI surface (ADR-0099 / CFP P1).

‎scripts/check_vm_parity.sh‎

Lines changed: 41 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
#!/usr/bin/env bash
2-
# scripts/check_vm_parity.sh — VM-backend parity probe (ADR-0070 / D-196).
2+
# scripts/check_vm_parity.sh — NON-DEFAULT-backend e2e sweep (D-553; was the
3+
# ADR-0070 / D-196 VM-parity probe).
34
#
4-
# Builds cljw with `-Dbackend=vm` (ReleaseSafe) and runs the clj-grounded
5-
# corpus + the (now-empty) D-196 VM-parity-blocker e2e list against it.
5+
# Builds cljw with `-Dbackend=tree_walk` (the F-012 differential-oracle
6+
# backend; `vm` is the production default since ADR-0070 step 4) and runs the
7+
# corpus + the FULL test/e2e suite against it — so an oracle-only e2e /
8+
# rendering regression cannot hide behind the vm-default gate.
69
#
7-
# HISTORY: this probe existed to stop VM gaps being MASKED by the (then)
8-
# tree_walk default — the per-commit gate ran e2e on tree_walk only. ALL 5
9-
# D-196 blockers closed 2026-06-02, and **build.zig's default flipped to `vm`**
10-
# (ADR-0070 step 4 / F-012). Post-flip the per-commit gate runs e2e on vm (the
11-
# production default), so the masking concern this probe guarded is resolved.
10+
# Cadence: on-demand / Phase boundaries (ADR-0049 per-commit-cost concern),
11+
# NEVER per-commit. Runtime ≈ one serial e2e pass (~5 min).
1212
#
13-
# CURRENT ROLE (on-demand): a `-Dbackend=vm` ReleaseSafe + corpus smoke. The
14-
# BLOCKERS list is empty (kept as the re-add point should a future VM-only
15-
# regression need tracking). FOLLOW-UP (tracked): repurpose to exercise the
16-
# e2e suite on the NON-default backend (`tree-walk`, the differential oracle)
17-
# so an oracle-only e2e/rendering regression can't hide behind the vm-default
18-
# gate — run on-demand / at Phase boundaries per ADR-0049's per-commit-cost
19-
# concern, not as a per-commit gate.
13+
# SKIPS lists e2e steps that intrinsically exercise the DEFAULT backend
14+
# (AOT bytecode / build pipeline) and are meaningless or false-failing on
15+
# tree-walk; each entry carries its reason. A newly-failing step NOT in
16+
# SKIPS is a genuine tree-walk regression — fix it, don't add it here
17+
# without a reason.
18+
#
19+
# HISTORY: the D-196 blocker era (VM gaps masked by the then-tree_walk
20+
# default) closed 2026-06-02; build.zig's default flipped to vm. This script
21+
# then idled as a corpus-only probe until the D-553 repurpose (2026-07-06).
2022
#
2123
# Restores the DEFAULT (vm ReleaseSafe wasm — the unified gate config)
2224
# binary on exit.
@@ -25,53 +27,46 @@
2527
set -uo pipefail
2628
cd "$(dirname "$0")/.."
2729

28-
# D-196 blocker e2e (basename under test/e2e/, minus .sh). Prune as gaps close.
29-
BLOCKERS=(
30-
# ALL D-196 blockers CLOSED 2026-06-02 — the list is empty; the probe now
31-
# verifies the corpus + (the absence of) regressions on -Dbackend=vm. Per
32-
# ADR-0070 step 4 the next cycle flips build.zig default to vm and promotes
33-
# this probe to a hard per-commit gate.
34-
# phase14_ns_directive CLOSED 2026-06-02 (D-098): op_ns_with_filter +
35-
# ns_filters side-table + emitLibspec loop. Pruned.
36-
# phase14_java_static_dispatch CLOSED 2026-06-02 (D-196 blocker 3): the
37-
# java-surface ctor `(java.io.File. …)` now resolves on the VM via the
38-
# shared special_forms.constructInstance (was deftype-only). Pruned.
39-
# phase14_catch_keyword CLOSED 2026-06-02 (D-014b VM lowering):
40-
# op_match_type_keyword parallels op_match_class. Pruned.
41-
# phase14_with_context + phase14_user_throw CLOSED 2026-06-02 (ADR-0071):
42-
# the cleanup-handler kind (op_push_cleanup / op_reraise) preserves the
43-
# dynamic error-context + catalog Kind through a binding / bare-try
44-
# unwind, matching TreeWalk's `defer`. Pruned from the blocker list.
45-
# NOTE: phase14_eval is NOT a VM blocker — `eval` is unimplemented on BOTH
46-
# backends (name_error), tracked separately as D-197. Do not add here.
30+
# e2e basenames (minus .sh) that are DEFAULT-BACKEND-specific by design.
31+
SKIPS=(
32+
# (populated empirically; empty = the whole suite is backend-neutral)
4733
)
4834

4935
restore() { zig build -Dwasm -Doptimize=ReleaseSafe >/dev/null 2>&1 || true; }
5036
trap restore EXIT
5137

52-
echo "check_vm_parity: building -Dbackend=vm -Doptimize=ReleaseSafe…"
53-
if ! zig build -Dwasm -Doptimize=ReleaseSafe -Dbackend=vm >/tmp/vmp_build.txt 2>&1; then
54-
echo "check_vm_parity: VM BUILD FAILED (see /tmp/vmp_build.txt)"; exit 1
38+
echo "check_vm_parity: building -Dbackend=tree_walk -Doptimize=ReleaseSafe…"
39+
if ! zig build -Dwasm -Doptimize=ReleaseSafe -Dbackend=tree_walk >/tmp/vmp_build.txt 2>&1; then
40+
echo "check_vm_parity: tree-walk BUILD FAILED (see /tmp/vmp_build.txt)"; exit 1
5541
fi
5642
export CLJW_SKIP_BUILD=1
5743

5844
fails=0
5945
if bash scripts/check_corpus_regression.sh >/tmp/vmp_corpus.txt 2>&1; then
60-
echo " corpus : ok ($(tail -1 /tmp/vmp_corpus.txt))"
46+
echo " corpus : ok ($(tail -1 /tmp/vmp_corpus.txt))"
6147
else
62-
echo " corpus : FAIL ($(tail -1 /tmp/vmp_corpus.txt))"; fails=$((fails + 1))
48+
echo " corpus : FAIL ($(tail -1 /tmp/vmp_corpus.txt))"; fails=$((fails + 1))
6349
fi
6450

65-
for name in "${BLOCKERS[@]}"; do
66-
t="test/e2e/$name.sh"
67-
[ -f "$t" ] || { echo " MISSING : $name"; continue; }
68-
if timeout 120 bash "$t" >/tmp/vmp_e2e.txt 2>&1; then
69-
echo " CLOSED : $name (passes on VM — prune from BLOCKERS)"
51+
is_skipped() {
52+
local n="$1"
53+
for s in "${SKIPS[@]:-}"; do [ "$s" = "$n" ] && return 0; done
54+
return 1
55+
}
56+
57+
for t in test/e2e/*.sh; do
58+
name="$(basename "$t" .sh)"
59+
if is_skipped "$name"; then
60+
echo " SKIP (default-backend) : $name"
61+
continue
62+
fi
63+
if timeout 180 bash "$t" >/tmp/vmp_e2e.txt 2>&1; then
64+
: # green — stay quiet (the suite is ~250 steps)
7065
else
71-
echo " blocker : $name ($(grep -iE 'FAIL|NotImplemented' /tmp/vmp_e2e.txt | head -1 | cut -c1-80))"
66+
echo " FAIL on tree-walk : $name ($(grep -iE 'FAIL|error' /tmp/vmp_e2e.txt | head -1 | cut -c1-100))"
7267
fails=$((fails + 1))
7368
fi
7469
done
7570

76-
echo "check_vm_parity: $fails failing group(s) over corpus + ${#BLOCKERS[@]} D-196 blockers on -Dbackend=vm"
71+
echo "check_vm_parity: $fails failing group(s) (corpus + full e2e) on -Dbackend=tree_walk"
7772
exit "$fails"

0 commit comments

Comments
 (0)