Skip to content

ci: build the playground with the real emcc on every PR; [99i3] names itself an approximation (#1255) - #1267

Merged
InauguralPhysicist merged 4 commits into
mainfrom
ci/wasm-real-build-1255
Sep 23, 2026
Merged

InauguralPhysicist merged 4 commits into
mainfrom
ci/wasm-real-build-1255

Conversation

@InauguralPhysicist

Copy link
Copy Markdown
Collaborator

Part 2 of #1255. The local gate [99i3] compiled with host clang -m32 (i386 ABI, double aligned 4) while the playground is wasm32 (double aligned 8): a layout _Static_assert could pass the gate and fail the real build — measured 12 vs 16 bytes on a probe struct; the Value union was 36 vs 40. Following #1264 (build the real target, as mature languages do):

  • pages.yml's build (the one emcc recipe, web/build.sh) now runs on pull_request; Pages configure/upload/deploy stay main-only.
  • tools/ilp32_syntax_check.sh: real emcc verdict when emcc is on PATH, otherwise an explicitly labelled APPROXIMATION pointing at the CI lane; new self-test rows 1w/1wt pin the i386-vs-wasm32 blind spot.
  • CI witness: draft PR PLANT — do not merge: wasm32-only layout assert (#1255 CI witness) #1266 plants a wasm32-only layout assert.

Draft while the blind-critic round runs.

Refs #1255 #1264

🤖 Generated with Claude Code

… itself an approximation (#1255)

pages.yml ran only on push to main, so the wasm32 build of web/build.sh was
first attempted after a merge and stayed red on main for five commits while
[99i3] (clang -m32) was green: i386 aligns double to 4 inside a struct and
wasm32 to 8, so a layout _Static_assert can pass -m32 and fail emcc.

- pages.yml: the build job also runs on pull_request (same path filter, same
  `bash web/build.sh`, no second copy of the emcc flags). Configure Pages, the
  artifact upload and deploy are gated to non-PR events; a PR gets its own
  concurrency group so it cannot cancel a main deploy.
- tools/ilp32_syntax_check.sh: with emcc on PATH, every recorded TU is
  compiled by the real emcc (-fsyntax-only, the call's recorded flags plus its
  -s settings) and the verdict is AUTHORITATIVE; otherwise the -m32 arm runs
  and the verdict/OK lines say APPROXIMATION and name pages.yml as the
  authority. Population, examined == len > 0, floor and all plants unchanged.
  New self-test control 1w (the -m32 arm passes a 12-vs-16 layout assert) and
  plant 1wt (the wasm32 frontend refuses it) pin the limit from both sides;
  with emcc on PATH the real arm is also driven and must be red.
- [99i3]: label and comment no longer claim the build "cannot break
  unnoticed"; requires the verdict: line and reads OK/macro_parity for that
  mode; case count 55 -> 57.
- werror_switch_check: ilp32 script floor 12 -> 14 (the real-emcc compile line
  and plant 1wt, measured with --print-counts).
- docs/CI.md (new section + check row), docs/PERFORMANCE.md, CHANGELOG;
  docs_claims_populations PATHS|docs/CI.md 53 -> 63.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@codspeed

codspeed Bot commented Sep 23, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 12 untouched benchmarks


Comparing ci/wasm-real-build-1255 (ca33f16) with main (57de58f)

Open in CodSpeed

InauguralPhysicist and others added 2 commits September 22, 2026 21:34
…ayground check reports on every PR

Gap 1 (oracle): round 1's real-emcc arm compiled each TU with -Isrc,
-DEIGENSCRIPT_EXT_*=0, -DEIGENSCRIPT_VERSION and -Werror=* that web/build.sh
never passes, so a recipe the driver rejects printed `verdict: AUTHORITATIVE`,
rc 0 (`#include "vm.h"`; deleting -DEIGENSCRIPT_VERSION). The arm now replays
each recorded call through the driver path resolved at startup: the recorded
argv, from the recorded cwd, with its stdin, plus -fsyntax-only, minus the -o
operand and the call's sibling TUs, each change argued in replay_argv_for_tu.
The -m32 arm drops the same injected -Isrc/-D (same argument) and compiles
from the recorded cwd. New self-test rows 10i/10d (real arm, against a wasm32
clang stand-in driver), 10im/10dm (-m32 arm), control 10c; each gut (re-add
the injected flags to either arm) turns its rows red. Cases 57 -> 62.

Gap 2 (feature): pages.yml's path-filtered PR trigger could never be a
required check. It now runs on every PR, unfiltered, as ci.yml's pattern:
`playground / scope` (the one path list), `playground / build` worker (same
`bash web/build.sh`, steps guarded, a built=true receipt), and the
aggregator `playground (real emcc wasm32 build)` (if: always(); a failed,
cancelled or skipped worker, or a touched PR with no receipt, is failure).
Deploy needs the aggregator and stays push-only. docs/CI.md names the
aggregator as the check to require.

werror_switch_check ilp32 floor 14 -> 13 (the real arm has no compile line of
its own now; --print-counts said 13).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ed?" decision

Round 2's `playground / scope` decided "touched" from `git diff --name-only`,
which under default rename detection lists only a renamed file's NEW path:
moving src/trace.h -> attic/trace.h (or src/hash.c -> tools/hash.c) read as
untouched, the build was skipped and the aggregator passed a recipe that no
longer compiles (both critic families). Round 1's path filter was the same
class. The build is ~72 s against a ~45 min CI run, so the decision is
deleted, not patched: the scope job and its path list are gone, the worker
runs `bash web/build.sh` on every PR and push with no condition upstream of
it (only the Pages steps stay gated to non-PR events), and the aggregator
`playground (real emcc wasm32 build)` is success iff the worker succeeded
and left its built=true receipt. The aggregator is kept: a skipped job reads
as passing to a required-check rule and a cancelled one leaves nothing; it
makes both a failure and keeps the requirable name. Deploy needs it and
stays push-only.

docs/CI.md and CHANGELOG say what is now true; docs_claims PATHS|docs/CI.md
63 -> 60 (the deleted path-list paragraph).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@InauguralPhysicist
InauguralPhysicist marked this pull request as ready for review September 23, 2026 03:08
…ly one reason

- tools/ilp32_syntax_check.sh header: the authoritative pages.yml build runs
  on EVERY pull request and push to main (round 3), not only on PRs touching
  src/web/docs/VERSION.
- docs/CI.md: the check to require is the aggregator, "never the worker
  alone" — the `scope` job it named no longer exists.
- Self-test plant 1: with -Isrc gone from the -m32 arm, the lone planted
  eigenscript.h copy could not resolve "value_slot.h", so the plant was red
  twice (the static assert AND a fatal missing include that masked every line
  past eigenscript.h:1666). The plant dir now stages src/'s headers (the
  recipe's own resolution, no -I re-injected), the UNPLANTED copy must compile
  clean there first, and the planted compile must yield exactly ONE error —
  the planted assert. Guts verified: staging only the lone header fails the
  control; bypassing the control too fails the one-error assertion (2 errors).
  Case count unchanged (62).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant