Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -281,10 +281,13 @@ jobs:
echo "${{ steps.clj.outputs.version }}" > .gold-clojure-version
echo "Goldens verified against Clojure ${{ steps.clj.outputs.version }}."

# Differential self-AOT execution gate: builds let-go twice (bytecode +
# -tags gogen_ir native) and diffs the output of every test/gold-aot/*.lg
# fixture across the two engines. A new cross-engine divergence fails the PR;
# known divergences are tracked in the shrink-only test/gogen_aot_xfail.txt.
# Engine parity gate + differential engine-output check: `make gogen-diff`
# first runs the complete-corpus engine parity gate (strict capability and
# output census over every test/gold-aot/*.lg fixture, enforcing the committed
# case ledger test/parity-ledger.txt plus the shrink-only partial and
# divergence baselines), then runs TestGogenAOTDiff, which builds let-go twice
# (bytecode + -tags gogen_ir native) and diffs fixture output across the two
# engines. A new case, status change, or cross-engine divergence fails the PR.
gogen-diff:
name: gogen-diff
runs-on: ubuntu-latest
Expand Down
61 changes: 52 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ GO-TEST-ENV := GOMEMLIMIT=$(GOMEMLIMIT)
GO-TEST-FLAGS := -timeout $(GO-TEST-TIMEOUT)


.PHONY: all default run build

all: build

# Start repl by default:
default:: run

Expand Down Expand Up @@ -162,7 +166,13 @@ $(LG-PROFILE): $(GO) $(ROOT-GO-FILES) pkg/**/* pkg/rt/core_compiled.lgb
# They are testing.Short()-gated and run full in dedicated CI jobs
# (.github/workflows/go.yml "Expensive lowering e2e" + the gogen-diff job), so
# the local `make test` loop stays fast without losing CI coverage.

.PHONY: test-gogen-diff-gate
test-gogen-diff-gate:
@scripts/test-gogen-diff-short.sh

test: pkg/**/* pkg/rt/core_compiled.lgb $(GO)
@scripts/test-gogen-diff-short.sh
$(GO-TEST-ENV) go test $(GO-TEST-FLAGS) -short -count=1 -v ./test/...

clojure-compat-report: $(GO)
Expand Down Expand Up @@ -221,16 +231,47 @@ check-selfhost: lowered $(GO)
fi; \
rm -rf "$$tmp" .selfhost-lgbgen; exit $$rc

# Differential self-AOT execution gate: build let-go twice (bytecode + the
# -tags gogen_ir native), run each test/gold-aot/*.lg fixture under both, and
# diff the last output line. A new cross-engine divergence fails; the
# shrink-only allowlist test/gogen_aot_xfail.txt tracks known ones. `lowered`
# keeps the gogen_ir tree fresh so the native build reflects current sources.
# Re-seed the allowlist (after a reviewed change) with:
# LETGO_AOT_REDERIVE=1 go test -run TestGogenAOTDiff -count=1 ./test/e2e/
# Differential engine-output gate: first run the complete-corpus strict
# capability/parity census, then retain the existing non-strict differential
# check. Both mandatory legs force full mode even when GOFLAGS contains -short.
.PHONY: gogen-diff
gogen-diff: lowered $(GO)
go test -run TestGogenAOTDiff -count=1 -v ./test/e2e/
gogen-diff: engine-parity-gate
go test -short=false -run TestGogenAOTDiff -count=1 -v ./test/e2e/

# Complete-corpus engine-output parity and strict-capability gate. The strict
# wrapper measures whether each fixture can execute with fallback forbidden; it
# does not prove fixture-source generated-Go or native-entry execution.
# The gate always logs a deterministic sorted coverage report: per-fixture
# category plus the measured lowering reason behind every non-full fixture, and
# a bucket census of distinct reasons. Report content is informational: it never
# changes classification, ratchets, or rederive. The one exit-status coupling is
# deliberate — an explicitly requested report write that fails is reported as a
# test error. Save a copy with:
# LETGO_PARITY_REPORT=/tmp/parity-report.txt make engine-parity-gate
# The gate also enforces the committed case ledger test/parity-ledger.txt: a
# diffable record of every measured case plus tombstones for removed fixtures.
# A normal run fails with per-case ADDED / REMOVED / STATUS-CHANGED lines, on a
# reappearing tombstoned fixture, and on any UNEXPLAINED tombstone.
# Re-derive the ledger and both neutral shrink-only baselines (written as one
# rollback-safe set) after a reviewed improvement with:
# LETGO_PARITY_REDERIVE=1 make engine-parity-gate
# Explain fixtures that disappear in the same rederive; unexplained tombstones
# fail later runs:
# LETGO_PARITY_TOMBSTONE_REASON="a.lg=merged into b.lg;c.lg=obsolete" \
# LETGO_PARITY_REDERIVE=1 make engine-parity-gate
# Drop tombstones inherited from earlier revisions (keeping this revision's) with:
# LETGO_PARITY_LEDGER_CLEANUP=1 LETGO_PARITY_REDERIVE=1 make engine-parity-gate
# A revision is the jj change id when available, else the git commit; when the
# revision cannot be resolved, cleanup is skipped and nothing is dropped.
.PHONY: engine-parity-gate
engine-parity-gate: lowered $(GO)
go test -short=false -run TestEngineParityGate -count=1 -v ./test/e2e/

# Historical compatibility aliases for existing local automation. The names
# predate the complete result-driven census; neither denotes a phase-limited or
# separately curated audit tier.
.PHONY: parity-gate-phase1 strict-audit
parity-gate-phase1 strict-audit: engine-parity-gate

# Default gate (~1 min): the jank suite under BOTH VM variants (bytecode +
# gogen_ir-lowered) + the calibration anchor. This is what CI runs.
Expand Down Expand Up @@ -264,6 +305,8 @@ bench-ratchet-full: lowered $(GO)
bench-ratchet-full-update: lowered $(GO)
go run ./cmd/bench-ratchet -full update

.PHONY: clean-lowered clean distclean

clean-lowered:
$(RM) -r pkg/rt/core_go_lowered
$(RM) lg_gogen_ir.go lg_gogen_accel.go cmd/lgbgen/main_gogen_ir.go cmd/lgbgen/main_gogen_accel.go pkg/ir/zz_gogen_ir_wire_test.go pkg/ir/zz_gogen_accel_wire_test.go pkg/wasmhost/zz_gogen_ir_wire_test.go pkg/rt/generated.provenance
Expand Down
42 changes: 42 additions & 0 deletions scripts/test-gogen-diff-short.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/bin/sh
set -eu

repo_root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
tmp_dir=$(mktemp -d "${TMPDIR:-/tmp}/letgo-gogen-diff-short.XXXXXX")
trap 'rm -rf "$tmp_dir"' EXIT HUP INT TERM

probe_file="$tmp_dir/probe"
fake_go="$tmp_dir/go"
cat >"$fake_go" <<'FAKE_GO'
#!/bin/sh
set -eu

record_leg() {
leg=$1
case " $* " in
*" -short=false "*) printf '%s\n' "$leg" >>"$PARITY_PROBE" ;;
*) printf '%s:skipped\n' "$leg" >>"$PARITY_PROBE" ;;
esac
}

case "$*" in
*TestEngineParityGate*) record_leg parity-audit "$@" ;;
*TestGogenAOTDiff*) record_leg gogen-diff "$@" ;;
esac
exit 0
FAKE_GO
chmod +x "$fake_go"

for target in gogen-diff parity-gate-phase1 strict-audit; do
PATH="$tmp_dir:$PATH" GOFLAGS=-short PARITY_PROBE="$probe_file" \
make -s -C "$repo_root" "$target" >/dev/null
done

expected="$tmp_dir/expected"
printf 'parity-audit\ngogen-diff\nparity-audit\nparity-audit\n' >"$expected"
if ! cmp -s "$expected" "$probe_file"; then
echo "gogen-diff and its parity/audit entry points must force -short=false on every mandatory leg" >&2
echo "observed:" >&2
sed 's/^/ /' "$probe_file" >&2
exit 1
fi
Loading
Loading