Skip to content

The deploy-floor CI lane builds the bundle it certifies but never boots it #196

Open

Description

@mparrett

Status, 2026-09-27

Done: the boot check exists in-repo. tests/browser/smoke.mjs waits for #app and asserts the Press any key title sentinel. deploy-pages.yml runs it and the tests/e2e suite before publishing, and pr-preview.yml runs it on PRs labelled deploy-preview. The Playwright scripts the body below points at live outside this repo.

To close this issue:

  • Run tests/browser/smoke.mjs against the bundle in test.yml's pinned lane, after the WASM build smoke step (l.112), which builds the bundle and never loads it. No branch or PR for this exists yet.
  • Decide whether the latest (upstream smoke test) lane gets the same step (it is continue-on-error, per the Scope section below).

pinned (deploy floor) in test.yml resolves .let-go-version, installs that let-go, compiles each test namespace, runs xsofy/test/run.lg, and runs the Layer-1 runtime smoke. It never runs make wasm, and never loads the result.

deploy-pages.yml resolves the same .let-go-version and builds the WASM bundle with it. So the lane named for the deploy floor exercises a different thing than the deploy does, and a let-go version that cannot build a working bundle passes it.

That is not hypothetical. The pin was stale in exactly that way until #195: on cf195a67, all three lane steps pass, and the bundle they certify dies at namespace load.

error loading xsofy.input: ExecutionError: calling dev?
  caused by bit-shift-left expected Int

Reproduced 3 runs out of 3 in headless Chromium under COI headers. The suite was green the whole time, because nothing in it builds the bundle. The gap had been open since 2026-07-16, when the SHA pin landed.

Suggested check

Two steps at the end of the pinned lane:

  1. make wasm — the id="app" guard already in the Makefile catches a stale builder, but only if something runs it in CI.
  2. Load dist/index.html in a headless browser with Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp, and fail on a page error or a missing title sentinel.

The COI headers are load-bearing: lg's wasm input ring is SharedArrayBuffer backed, so a plain static server boots to a read-key failure rather than the game, and the bundled coi-serviceworker.js fallback is not reliable under headless automation. local-scripts/coi-serve.py in the joint workspace exists for this, and the repo already carries Playwright smoke scripts under local-scripts/browser-smoke-playwright/ that could host the check.

Worth knowing if you reuse smoke.mjs as the starting point: it still waits for #terminal, which #378 renamed to #app, so it would need that one-line update to be meaningful against a current bundle.

Scope

This is about the floor lane specifically. The latest (upstream smoke test) lane has the same shape, and would benefit from the same two steps, but it is continue-on-error so a gap there is cheaper.

Happy to open the PR if the shape above looks right, or to take a different one if you would rather the boot check live in its own workflow than extend the matrix.

Activity

  1. changed the title [-]The deploy-floor CI lane never builds or boots the bundle it certifies[/-] [+]The deploy-floor CI lane builds the bundle it certifies but never boots it[/+] on Sep 20, 2026
  2. mparrett commented on Sep 20, 2026

    @mparrett
    CollaboratorAuthor

    Correction to the title and the opening paragraph: the lane does build the bundle. test.yml's WASM build smoke step has run the build-wasm action since #69, so it builds exactly what deploy-pages.yml builds. What it never does is load the result.

    That makes the gap narrower and more specific than filed, not wider. The failure quoted below is at namespace load, so a build-only lane passes it by construction — adding make wasm would change nothing, and only a headless boot closes it.

    Reproduced again on 2026-09-20 in headless Chromium under COI headers, with the bundle built from the #195 branch at the old pin cf195a67. Worth recording how it surfaces, since it defeats the obvious checks: it arrives on console.log rather than console.error or stderr, and the format string is botched (error loading %s: %v printed literally, arguments trailing in %!(EXTRA ...)), so neither an error-channel watcher nor a grep for the assembled message finds it. A boot gate has to assert the title screen appears, not that no error was logged.

    Title corrected. Same wrong claim was in #195's body and .let-go-version; both fixed there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions