Skip to content

A verified Web run that asked the host for node (2026.9.12.1) - #617

Merged
Sunrisepeak merged 1 commit into
mainfrom
fix/wasm-runner-from-the-payload
Sep 11, 2026
Merged

A verified Web run that asked the host for node (2026.9.12.1)#617
Sunrisepeak merged 1 commit into
mainfrom
fix/wasm-runner-from-the-payload

Conversation

@Sunrisepeak

Copy link
Copy Markdown
Member

Carries version 2026.9.12.1. Design record: .agents/docs/2026-09-12-a-verified-web-run-that-asked-the-host-for-node.md.

What was measured

The sandbox verification of the published 2026.9.11.4 held on 26 of 27 checks in an xlings subos use <name> --sandbox environment, which has no node on PATH. The one that did not was the Web run: mcpp build --target wasm32-emscripten succeeded, and mcpp run stopped at

/usr/bin/env: 'node': No such file or directory

An Emscripten link produces a JavaScript launcher whose first line is #!/usr/bin/env node. With nothing declared, mcpp executes the artefact, so the interpreter came from the PATH mcpp inherited. Meanwhile the node that xim:emsdk declares, and writes into its own .emscripten, sat in the store. The development host has node on PATH, which is why no earlier measurement could see the dependency.

The change

The payload names the program that runs what it produces: .mcpp-toolchain.json gains a fourth key, runner.

  • One program, no arguments. The artefact path is appended, so the key cannot carry flags.
  • Relative or absolute. A relative runner obeys the frontend rules. An absolute runner is honoured only inside the package store that holds the payload, compared on canonical paths, and a runner outside the store is ignored, so a payload cannot choose a host interpreter.
  • Malformed values are refused by name. The path rules are now one helper shared by frontend and runner, and the frontend messages are unchanged.
  • Last in precedence, run slot only. [target.<triple>] runner and a dependency's mcpp::runner(...) outrank it, and --no-runner still executes the artefact directly.

xim:emsdk writes the key: openxlings/xim-pkgindex#823, merged and published (index artifact 971571a). An engine that predates the key ignores it. A payload installed before the recipe change has no descriptor and runs as before.

Verification

  • Unit: five new descriptor tests. With the store rule removed, ARunnerOutsideTheStoreIsNotHonoured fails.
  • Sandbox, no node on PATH, a musl-static build of this tree:
    • with a descriptor in the sandbox's emsdk payload, the run prints 1-2-3;
    • with the descriptor removed, it fails at /usr/bin/env: 'node' again.
  • CI: scan (linux-x86_64) runs a Web program with a fresh MCPP_HOME, so the payload is the one the index publishes rather than a cached one. A decoy node sits first on PATH and exits 97 with a marker. The step fails if the payload has no descriptor, if the decoy ran, or if 1-2-3 is not a line of the output.

Docs

docs/20-toolchains.md and its Chinese copy state where the interpreter comes from. Both READMEs and examples/13-platform-targets no longer imply a node from PATH. The CHANGELOG has the 2026.9.12.1 entry.

The sandbox verification of the published 2026.9.11.4 held on 26 of 27
checks. The one that did not was the Web run: `mcpp build --target
wasm32-emscripten` succeeded, and `mcpp run` stopped at

    /usr/bin/env: 'node': No such file or directory

An Emscripten link produces a JavaScript launcher whose first line is
`#!/usr/bin/env node`. With nothing declared, mcpp executes the artefact, so the
interpreter came from the PATH mcpp inherited, while the node `xim:emsdk`
declares, and writes into its own `.emscripten`, sat in the store. The
development host has node on PATH, which is why no earlier measurement,
including the dry run of the verification script, could see it.

THE PAYLOAD NAMES THE PROGRAM THAT RUNS WHAT IT PRODUCES. `.mcpp-toolchain.json`
gains a fourth key, `runner`:

  - one program, no arguments; the artefact path is appended, so the key cannot
    carry flags
  - relative to the payload under the rules `frontend` obeys, or absolute and
    honoured only inside the package store that holds the payload, compared on
    canonical paths; a runner outside the store is ignored, so a payload cannot
    choose a host interpreter
  - structurally malformed values are refused by name at read time; the path
    rules are now one helper shared by `frontend` and `runner`, with the
    `frontend` messages unchanged
  - last in precedence and in the run slot only: a project's
    `[target.<triple>] runner` and a dependency's `mcpp::runner(...)` outrank
    it, and `--no-runner` still executes the artefact directly

`xim:emsdk` writes the key (openxlings/xim-pkgindex#823). An engine that
predates it ignores it, and a payload installed before the recipe change has no
descriptor and runs as before.

Measured:
  - unit: five new descriptor tests; with the store rule removed,
    ARunnerOutsideTheStoreIsNotHonoured fails
  - sandbox, no node on PATH, a musl-static build of this tree: with a
    descriptor in the sandbox's emsdk payload the run prints 1-2-3; with it
    removed the run fails at `/usr/bin/env: 'node'` again. The first attempt
    used the glibc development binary, whose loader lives in the host's
    ~/.mcpp, and measured nothing
  - CI: `scan (linux-x86_64)` runs a Web program with a fresh MCPP_HOME and a
    decoy `node` first on PATH that exits 97 with a marker

Docs: docs/20-toolchains.md and its Chinese copy state where the interpreter
comes from; both READMEs and examples/13 no longer imply a node from PATH. The
design record is .agents/docs/2026-09-12-a-verified-web-run-that-asked-the-host-for-node.md.
@Sunrisepeak
Sunrisepeak merged commit c688fca into main Sep 11, 2026
39 checks passed
@Sunrisepeak
Sunrisepeak deleted the fix/wasm-runner-from-the-payload branch September 11, 2026 17:28
Sunrisepeak pushed a commit that referenced this pull request Sep 12, 2026
…s its runner

The sandbox verification of 2026.9.12.2 measured that removing and reinstalling an emsdk payload installed before openxlings/xim-pkgindex#823 reproduces the missing runner: mcpp refreshes its index copy when a resolution misses, not because a recipe changed. After 'mcpp index update' the snapshot's recipe writes the descriptor, the reinstalled payload names its runner, and the program prints its output. docs/20, its Chinese copy, the CHANGELOG entry and the #617 record now state the three steps and point at #621 for the missing diagnostic; the engine-gaps record adds the two findings the verification produced.
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.

2 participants