From f76a73b6a36ee61de1cd673c6bf70556c7a634e2 Mon Sep 17 00:00:00 2001 From: Lann Martin Date: Mon, 10 Aug 2026 22:45:59 -0400 Subject: [PATCH] Consume deltic from JSR: packaged translator, repo-built browser assets --- AGENTS.md | 22 ++--- js/runner-deltic/README.md | 60 ++++++++----- js/runner-deltic/browser-bundle-entry.ts | 18 ++++ js/runner-deltic/browser-worker.mjs | 6 +- js/runner-deltic/deno.json | 34 +++++-- js/runner-deltic/deno.lock | 99 ++++++++------------- js/runner-deltic/engine.mjs | 3 +- js/runner-deltic/fetch-deltic.ts | 108 ----------------------- js/runner-deltic/runner.ts | 24 +++-- js/runner-deltic/worker-main.mjs | 2 +- js/viewer/deltic.mjs | 3 +- justfile | 103 +++++++++++++++++---- 12 files changed, 246 insertions(+), 236 deletions(-) create mode 100644 js/runner-deltic/browser-bundle-entry.ts delete mode 100644 js/runner-deltic/fetch-deltic.ts diff --git a/AGENTS.md b/AGENTS.md index 6900603..6923360 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -88,9 +88,9 @@ with copies; symlinks require `core.symlinks` on Windows. wasmtime 47 (`-W component-model-async -S p3`), wac-cli 0.10, wit-bindgen 0.60, Node 24 (plain — the selftest legs; no engine flags anywhere: -deltic's callback ABI needs no JSPI), deno 2.9 (deltic asset fetching + -runner leg; deltic itself is release-pinned — see -`js/runner-deltic/README.md`), Rust +deltic's callback ABI needs no JSPI), deno 2.9 (deltic runner +leg + browser-asset build; deltic itself is consumed from JSR as exact +prerelease pins — see `js/runner-deltic/README.md`), Rust target `wasm32-wasip2`, wasm-tools (WIT validation), just (task runner). jco is GONE from this repo (the deltic migration's Phase 4 cutover); its findings in `docs/findings.md` are historical. Known @@ -144,14 +144,14 @@ them before committing anything cross-cutting): component-model-async -S p3`. Same sample-suite verdicts. 3. **deltic runner + browser leg** (see `js/runner-deltic/README.md`): drive the suite directly under deltic — no transpile step, no engine - flag; release-pinned in `js/runner-deltic/`. Same sample verdicts - (shared human + fold goldens); tag scheduling from the suite's own - embedded inventory (fixture leg runs `--missing hsm` like Paths 1/4, - lane goldens in `expected/verify-deltic-*`). The browser worker - (`browser-worker.mjs`, drop-in for `page-runner.mjs` via `workerUrl`) - shares `harness.mjs`'s case loop; `selftest.mjs` gates that engine - path under plain node as `verify-deltic`'s last leg. (The jco-node - runner that used to be this path was deleted in the deltic + flag; JSR-pinned in `js/runner-deltic/deno.json` + `deno.lock`. Same + sample verdicts (shared human + fold goldens); tag scheduling from the + suite's own embedded inventory (fixture leg runs `--missing hsm` like + Paths 1/4, lane goldens in `expected/verify-deltic-*`). The browser + worker (`browser-worker.mjs`, drop-in for `page-runner.mjs` via + `workerUrl`) shares `harness.mjs`'s case loop; `selftest.mjs` gates + that engine path under plain node as `verify-deltic`'s last leg. (The + jco-node runner that used to be this path was deleted in the deltic migration's Phase 4; `js/viewer/browser-worker.mjs` remains as consumer-facing glue for transpiled-module layouts.) 4. **Inventory + results pipeline**: diff --git a/js/runner-deltic/README.md b/js/runner-deltic/README.md index 43ea052..fc4f450 100644 --- a/js/runner-deltic/README.md +++ b/js/runner-deltic/README.md @@ -11,14 +11,16 @@ suites' `wasi:{cli,clocks,io,random,filesystem}` leaves. ```sh cargo build --target wasm32-wasip2 --release -p sample-suite # from repo root -translator=$(deno run --allow-read=js/runner-deltic,target --allow-write=target \ - --allow-net=github.com,objects.githubusercontent.com,release-assets.githubusercontent.com \ - js/runner-deltic/fetch-deltic.ts --asset translator) deno run --allow-read=target --config js/runner-deltic/deno.json --frozen \ js/runner-deltic/runner.ts target/wasm32-wasip2/release/sample_suite.wasm \ - --translator "$translator" [--jsonl] + [--jsonl] ``` +No fetch step and no extra permissions: the translator arrives with the +pinned `@deltic/translator` package and loads through the module graph +(`defaultTranslator()`). `--translator ` remains as a documented +escape hatch for an externally-sourced translator build. + Human mode reproduces `expected/verify-run-sample.txt` byte-for-byte (shared with the composed-cli and jco legs); `--jsonl` emits canonical L4 results JSONL (`just verify-deltic` diffs it, normalized, against @@ -35,9 +37,9 @@ cases out as `not-applicable`. `harness.mjs` case loop (striping, freshCases, timeouts, mark scheduling), no transpiled artifacts: the run message carries `{ bundleUrl, translatorUrl, suiteUrl, env?, missing?, only?, shard?, -caseTimeoutMs? }` and the worker loads the pinned `deltic-embedder.mjs` -release asset (one platform-neutral ES module: embedder API + -Translator + runner glue + wasi shims). It drops into +caseTimeoutMs? }` and the worker loads `deltic-embedder.mjs`, built by +`just deltic-assets` from the pinned JSR graph (one platform-neutral +ES module: embedder API + Translator + runner glue + wasi shims). It drops into `page-runner.mjs`'s `runSuitesInPage` via its `workerUrl` parameter — page runner and browser driver unchanged. `engine.mjs` is the shared glue; `selftest.mjs` drives the same engine path under plain `node` @@ -60,19 +62,35 @@ bundleUrl-loading defaults. ## Pinning -deltic is pinned to a release tag in **two** places, cross-checked at -run time by `fetch-deltic.ts`: +deltic is consumed from JSR as **exact-pinned unstable prereleases**: +every green deltic `main` commit publishes +`@deltic/{runtime,translator,wasi-shims,ct-runner}` as +`0.1.0-pre.g`, so one version names one upstream commit +(there is no stable line yet — hash versions are unordered and semver +ranges never resolve to prereleases). -- `deno.json` — import-map URLs (`raw.githubusercontent.com/lann/deltic//…`); - `deno.lock` carries integrity hashes for that module graph and is - enforced with `--frozen`. The `@deltic/runtime/embedder` entry exists - because `wasi-shims` imports it by bare specifier (resolved by the - workspace config inside deltic; URL consumers must map it). -- `fetch-deltic.ts` — `TAG` + per-asset sha256 for the - `deltic-translator-shim.wasm` and `deltic-embedder.mjs` release assets - (cached under `target/deltic//`; `--asset translator|embedder`). +- `deno.json` — the import map holds the five `jsr:@deltic/...@` + specifiers. `@deltic/runtime/embedder` is mapped because + `@deltic/wasi-shims` imports it by bare specifier. + `minimumDependencyAge` exempts the `@deltic` scope so same-day + publishes resolve (Deno >= 2.9 for the wildcard exclude). +- `deno.lock` — carries JSR package integrity for that graph and is + enforced with `--frozen` on every run, check, bundle, and + `deno info` invocation. +- No sha256 bookkeeping and no release-asset downloads: the browser-leg + assets are built from the same locked graph by `just deltic-assets` + into `target/deltic-browser/` — `deltic-embedder.mjs` bundled from + `browser-bundle-entry.ts`, and `deltic-translator-shim.wasm` copied + out of the lock-pinned module cache (the packaged + `@deltic/translator` asset). The directory is version-free: the lock + owns versioning. +- `just deltic-pin-gate` (a `verify-deltic` prerequisite, so it runs in + CI) asserts one version across every `@deltic` specifier in every + `deno.json` and everything the lock resolves — the successor to the + retired release-asset fetch script's `assertPinConsistency`. -To bump: update the tag in both files and the shas from the release's -`SHA256SUMS`, delete `deno.lock`, re-run -`deno cache runner.ts fetch-deltic.ts` in this directory, regenerate the -`expected/verify-deltic-*` goldens, and commit the diff. +To bump: update the version in `deno.json`'s import map, delete +`deno.lock`, re-run `deno install --entrypoint runner.ts +browser-bundle-entry.ts` in this directory, and commit the diff; the pin +gate asserts agreement. Regenerate the `expected/verify-deltic-*` +goldens only if an explained upstream behavior change moves them. diff --git a/js/runner-deltic/browser-bundle-entry.ts b/js/runner-deltic/browser-bundle-entry.ts new file mode 100644 index 0000000..706032f --- /dev/null +++ b/js/runner-deltic/browser-bundle-entry.ts @@ -0,0 +1,18 @@ +// The browser-leg bundle entry: one platform-neutral ES module carrying +// the embedder API + Translator + ct-runner glue + wasi shims, bundled +// from the SAME pinned JSR graph as the Deno leg (deno.json + deno.lock, +// --frozen). It replaces the sha-pinned `deltic-embedder.mjs` release +// asset the retired release-asset fetch script downloaded; the surface is +// upstream tools/release-bundle/entry.ts's, verbatim. +// +// deno bundle --config js/runner-deltic/deno.json --frozen \ +// --platform browser -o target/deltic-browser/deltic-embedder.mjs \ +// js/runner-deltic/browser-bundle-entry.ts +// +// (`just deltic-assets` builds it; verify-deltic/viewer-build consume it.) + +export * from "@deltic/runtime/embedder"; +export { Translator } from "@deltic/runtime/shim"; +export * from "@deltic/ct-runner"; +export { wasiShims } from "@deltic/wasi-shims"; +export type { WasiShims, WasiShimsOptions } from "@deltic/wasi-shims"; diff --git a/js/runner-deltic/browser-worker.mjs b/js/runner-deltic/browser-worker.mjs index 292e546..3d4a7cc 100644 --- a/js/runner-deltic/browser-worker.mjs +++ b/js/runner-deltic/browser-worker.mjs @@ -5,8 +5,10 @@ // worker's run message instead of the jco one: // // { -// bundleUrl, // the pinned deltic-embedder.mjs (release asset) -// translatorUrl, // the pinned deltic-translator-shim.wasm +// bundleUrl, // deltic-embedder.mjs, built from the pinned JSR +// // graph by `just deltic-assets` +// translatorUrl, // deltic-translator-shim.wasm, extracted from the +// // same locked graph (@deltic/translator's asset) // suiteUrl, // the suite COMPONENT wasm (no transpile, no cores) // env?, // [name, value] pairs for wasi:cli/environment // missing?, only?, shard?, caseTimeoutMs?, diff --git a/js/runner-deltic/deno.json b/js/runner-deltic/deno.json index 3709136..a180dd4 100644 --- a/js/runner-deltic/deno.json +++ b/js/runner-deltic/deno.json @@ -1,8 +1,32 @@ { + // MODULE IDENTITY — deltic is consumed from JSR as exact-pinned unstable + // prereleases: every green deltic `main` commit publishes + // `0.1.0-pre.g`, so the version below NAMES ONE upstream commit + // (there is no stable line yet; hash versions are unordered and semver + // ranges never resolve to prereleases, hence exact pins). All four + // packages must carry the SAME version — `just verify-deltic`'s pin gate + // asserts that repo-wide. + // + // `@deltic/runtime/embedder` is mapped because `@deltic/wasi-shims` + // imports it by bare specifier. `@deltic/translator` ships the translator + // wasm built from the same commit: the Deno leg loads it through the + // module graph (`defaultTranslator()`, permission-free) and the browser + // leg extracts it from the lock-pinned module cache — no release-asset + // fetch, no sha bookkeeping. `deno.lock` carries JSR package integrity + // and is enforced with `--frozen` everywhere. + // + // Bumping: change the version in these five specifiers, delete deno.lock, + // re-run `deno install --entrypoint runner.ts browser-bundle-entry.ts` in + // this directory, and commit the diff (see README.md "Pinning"). "imports": { - "@deltic/ct-runner": "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/ct-runner/src/mod.ts", - "@deltic/runtime/embedder": "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/embedder/mod.ts", - "@deltic/runtime/shim": "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/shim/mod.ts", - "@deltic/wasi-shims": "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/wasi-shims/src/mod.ts" - } + "@deltic/ct-runner": "jsr:@deltic/ct-runner@0.1.0-pre.ga67ee83", + "@deltic/runtime/embedder": "jsr:@deltic/runtime@0.1.0-pre.ga67ee83/embedder", + "@deltic/runtime/shim": "jsr:@deltic/runtime@0.1.0-pre.ga67ee83/shim", + "@deltic/translator": "jsr:@deltic/translator@0.1.0-pre.ga67ee83", + "@deltic/wasi-shims": "jsr:@deltic/wasi-shims@0.1.0-pre.ga67ee83" + }, + // Deno's supply-chain minimum-dependency-age gate (24h default) applies + // even to exact prerelease pins; deltic publishes per commit, so the + // scope is excluded (wildcard excludes need Deno >= 2.9; CI pins 2.9.5). + "minimumDependencyAge": { "age": "P1D", "exclude": ["jsr:@deltic/*"] } } diff --git a/js/runner-deltic/deno.lock b/js/runner-deltic/deno.lock index 281c48d..c13ad2c 100644 --- a/js/runner-deltic/deno.lock +++ b/js/runner-deltic/deno.lock @@ -1,66 +1,41 @@ { "version": "5", - "remote": { - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/ct-runner/src/context.ts": "366db52e3189260a7fd2fc2fdb90aea9bd6a3055d83c42acad082eb75565c634", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/ct-runner/src/import-analysis.ts": "64971e796ebccd98730ba2a0e78b599db38284f22b7976687fc4cad898703c32", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/ct-runner/src/mod.ts": "24a88cb8dda9c1d346a1809297cc5b2ab1c3a2d39c4914694c2ee5f76e9911db", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/ct-runner/src/run-suite.ts": "76d76ed7dfbeb7ce24410dfabadb8f1524fe6e1adb0428b7d361310168a44411", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/ct-runner/src/tags.ts": "d64136eb7e21e18e73cc255e052f59377d2be869f4929bf4fc6de026f3b74a0b", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/cabi/async_values.ts": "af1279d4e4db5b756268979aeff5b27c1cf6c0f021213655676ade90472f282b", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/cabi/context.ts": "b4b60891ef9d9e72b208636f6ba37f0b9b6962d307af6156ad3b5ad59a626902", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/cabi/flatten.ts": "6c980fe38d7adce349d5e028b819eb0ffbb92714f958c1d5daae8da3e7ed3889", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/cabi/float.ts": "0483e8c1aa8786eee4c6f6357fee6738555e4310650c474aba6cd811a80d7d36", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/cabi/handles.ts": "30510750261499f48a812bb8c349a8f88a3bb7239175e6f1d4e6d10c38571e5d", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/cabi/layout.ts": "8122141b39f4d8189c13d91fc1b37825ceead86988f879f3fa9351bbef96f8f2", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/cabi/lift.ts": "e4475a44a5618114f288025601b535bc04b97e9a37b3be21f51d3be092d419c8", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/cabi/load.ts": "c1d8ddb1b3b3c59afe30710a97ad6dd7ae1ecd59aa1d427a5eaf4552d3b1ea01", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/cabi/lower.ts": "916ef7476dc583783770f4c42de7a655350531b3763c81a92249cca96f5e4d80", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/cabi/memory.ts": "09728360d6413fb30a5a7bff1ba6abec1ac6474ff150d45f093b8ebe5e65cd51", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/cabi/mod.ts": "b79cf9e2bab2e837fee76fa61dc18bff66d941e08597f1b76de93811bd6d6008", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/cabi/store.ts": "97aaecfeb4dfbf5c3c132fb5eadf1f5677924936eee0c7fa75a266a00cd73634", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/cabi/strings.ts": "9589dda3857725792ae15ef6888449b48e973b9eb0f3058ed64e10bf4d39b793", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/cabi/trap.ts": "307d8b48806eeba30400b3d7db9370cee70a12298851c1c19053dd8ca0013e1c", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/cabi/types.ts": "d0392e8cdf2990a76c8a1f9b85795d3b7c19b8eb006c2b159b671d08c39b9535", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/cabi/values.ts": "9e6ddcc4192d05897b2cbea250db3fef0ad9bf6548ba87aff378ee14b7ab7022", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/embedder/casing.ts": "1e9083becfc08107c09015ce3db79c304b05c40085a3c899ea1c8ebe25fcd45f", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/embedder/errors.ts": "b0cac244526b92c052d165f2aee1d9492e5915a5a4cad114e1ab575ffe1587ba", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/embedder/imports.ts": "98cca003e4a1131c35854c91b458f109d6761a3e8f67c23730f7e9bc28bbad88", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/embedder/instantiate.ts": "2479c085a82adc20eb3e8e11832cad8daaa50992d383e8a38d73fbc7259f52e5", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/embedder/mod.ts": "0a4f42b8c569b528b4c3172c3394ad5f9ddafa33bcaf5eccd00e645e111da2b1", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/embedder/resources.ts": "d209e5f13545b9c0c095ac4e188b72370d97c9bd394ba7c8793ddd74f436b1ef", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/embedder/streams.ts": "4ef894a43da94b4cb01ee65798a108a8fb3f6b2dc6013c71881f63e0806df565", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/embedder/values.ts": "ed876f9103f4a4f34e8eb475934091156bee1447f5a029ea300644b8f3ee71eb", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/embedder/version.ts": "b1c589988e5fb88dce3a014846c9253399e286f12afb5fd92509c8d6090ad4bb", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/exec/boundary.ts": "8a162aefc3524ce1a72f294a95eadc92b66764de75bad84966301192a57ae92e", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/exec/executor.ts": "55044c381d842a9d0f17731d55b47b48023d3a9222806e4b0607b53615a1dc97", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/exec/host_streams.ts": "63f6b113806c401ae9895df82448da70a7745a97b6e2f04061fb5bc64e7d0acf", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/exec/mod.ts": "a46320977ece14342bcb72c9c9e36d65a1cd09d789591d0909d7d1185264010b", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/intrinsics/async_builtins.ts": "526795358da8908d54a483bb47eebc43e0a1ea59e69ece94d0c6890ad0fa8784", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/intrinsics/context.ts": "be93b23d127ff71d5c372781f89d1c3746c5d32a44e67ebbcd91f2b0f0807e93", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/intrinsics/errors.ts": "9d09fc1818b4dc98b238aa69008a9110d9d305b6a8e806604f3bd48fca1eebcb", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/intrinsics/fact_calls.ts": "aa0b0aef81b59cdcd8dc572c20e1f57a8f5592f75a0d5d666032851df9201229", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/intrinsics/mod.ts": "f9c095e561f5fbb51f70693b21f272f66241f2e8ff2e1a83cd4176bcd0104eb9", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/intrinsics/stream_builtins.ts": "bbc1e1ea0e4616026a46d790a68695aa70589a88b08a6275acdb525f0ab531ec", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/intrinsics/transcode.ts": "e3fcaeb7a60b6cbad999d9389d4bce59e305e6f54e035ba791f909e10d1f82c7", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/jspi/bridge.ts": "7cf3706d3bf34b503aea516a31918a8d930aba3dac7e94ec04caecd23fe6025e", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/jspi/mechanics.ts": "dc0fe4965b3ef8c0aff6674afd8bae2a38942ab934fa07fd2eb7db72b2462f17", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/jspi/mod.ts": "4d047b820b50c410ed946c62dc48286f8abe4787ce6ae5466cd0ae255d98943c", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/jspi/types.ts": "86929224733a764a148ac75a9d6b95d61ab4c8123a48fe956d998e97726a1432", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/plan/format.ts": "90e31bbc7137c2f80c0782e1431afb6f81827aab8d38dba1178b8761f1b3ea0a", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/plan/loader.ts": "107db77e724a7f74f161a5fd20e7110a6e6f182c46f18282eba650bc887dc876", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/shim/mod.ts": "34af2240dfd0be720def487db2db34eaad6ba9178003f20e2193d03a0632779b", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/shim/translator.ts": "7ea1a4101363ee62ddedb9d6c3f798fd6042886ef38ee13046ac3cdb9485bf24", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/task/mod.ts": "5decca8045dfd9743910e83d512258a7be3b0d0917954b8d9cdbac38e03f7dfb", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/task/scheduler.ts": "18a4404f620407bd867876115861ee0cf98f6f1ccd41c5f3c877ef90e429ef9c", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/task/streams.ts": "83b522a6393ba06fbdb87881bc6761f3fce9c03b85e9eda03d3befe7d2605a60", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/task/subtask.ts": "750b13a1318f62836bfd149f1b9144de5b017fd7a84adc8e2fb2151e63130fbc", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/task/thread.ts": "81fe38b37a1ec130803b478a24e428b19ee4e1ef8c0bae741395cd8d52751580", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/task/waitable.ts": "5e1fc092e3d8f1fb4429d6a91d8886b3e474aa9ac6254e7924fd896c4929e1f9", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/wasi-shims/src/cli.ts": "d1617e12dc2569f4ee107f8b92488797daf431d14b8a86a1ab10750a28757394", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/wasi-shims/src/clocks.ts": "05468a822b635408ce3a671b40fd06fd4448c220019f9449bf029ac1c7e59664", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/wasi-shims/src/filesystem.ts": "6dcead5346d78084c3923410e44875e678f3b58db0c2d59513339b428596ec25", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/wasi-shims/src/io.ts": "dfe270e5ad3388c02696e27a5c69c58a411759fe8c99416361b0ac10177366da", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/wasi-shims/src/mod.ts": "1748985cf851252e1755aafd9ebb9c7ae96003ec41322d9524a952062d2b8570", - "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/wasi-shims/src/random.ts": "dc04d20de5399cc7fa8685a04ec954618e3994a374ef94535fff408a745425e2" + "specifiers": { + "jsr:@deltic/ct-runner@0.1.0-pre.ga67ee83": "0.1.0-pre.ga67ee83", + "jsr:@deltic/runtime@0.1.0-pre.ga67ee83": "0.1.0-pre.ga67ee83", + "jsr:@deltic/runtime@~0.1.0-pre.ga67ee83": "0.1.0-pre.ga67ee83", + "jsr:@deltic/translator@0.1.0-pre.ga67ee83": "0.1.0-pre.ga67ee83", + "jsr:@deltic/wasi-shims@0.1.0-pre.ga67ee83": "0.1.0-pre.ga67ee83" + }, + "jsr": { + "@deltic/ct-runner@0.1.0-pre.ga67ee83": { + "integrity": "d78e96eba54e53dabe7c1de5a67782aad755362824d741913ab4d36941ebfbcc", + "dependencies": [ + "jsr:@deltic/runtime@~0.1.0-pre.ga67ee83" + ] + }, + "@deltic/runtime@0.1.0-pre.ga67ee83": { + "integrity": "2a2b0949031747a2340dc186299e654ea9f361ae39ac6bd633019940682db4ed" + }, + "@deltic/translator@0.1.0-pre.ga67ee83": { + "integrity": "e4f1bb219e56b62262b0c9665e3f6646aa13883b2cfbb9d6306f69d19974d412", + "dependencies": [ + "jsr:@deltic/runtime@~0.1.0-pre.ga67ee83" + ] + }, + "@deltic/wasi-shims@0.1.0-pre.ga67ee83": { + "integrity": "a5754e65d50873e675695a51279989e22b3771e31f16a84a09feb15905c574a7", + "dependencies": [ + "jsr:@deltic/runtime@~0.1.0-pre.ga67ee83" + ] + } + }, + "workspace": { + "dependencies": [ + "jsr:@deltic/ct-runner@0.1.0-pre.ga67ee83", + "jsr:@deltic/runtime@0.1.0-pre.ga67ee83", + "jsr:@deltic/translator@0.1.0-pre.ga67ee83", + "jsr:@deltic/wasi-shims@0.1.0-pre.ga67ee83" + ] } } diff --git a/js/runner-deltic/engine.mjs b/js/runner-deltic/engine.mjs index c72b57d..838d008 100644 --- a/js/runner-deltic/engine.mjs +++ b/js/runner-deltic/engine.mjs @@ -1,5 +1,6 @@ // Shared engine glue for the deltic legs (browser shard worker + Node -// selftest): load the pinned deltic embedder bundle, translate the suite +// selftest): load the repo-built deltic embedder bundle (`just +// deltic-assets`, from the pinned JSR graph), translate the suite // component, and hand back exactly what harness.mjs `runCases` needs. // deltic is a runtime linker — the suite arrives as the COMPONENT wasm // (no transpiled module, no core files, no imports module; WASI comes diff --git a/js/runner-deltic/fetch-deltic.ts b/js/runner-deltic/fetch-deltic.ts deleted file mode 100644 index a0af396..0000000 --- a/js/runner-deltic/fetch-deltic.ts +++ /dev/null @@ -1,108 +0,0 @@ -// Fetch (and cache) deltic release assets for the pinned release. -// -// deltic is a runtime linker: components are translated by a wasm build of -// its translator, and browser/Node consumers load the runtime as one -// platform-neutral ES module (`deltic-embedder.mjs`) — both shipped as -// release assets so consumers need no Rust or Deno toolchain. This script -// downloads one asset into target/deltic//, verifies it against the -// pinned sha256, and prints the cached path on stdout (the `verify-deltic` -// recipe captures it). -// -// deno run … fetch-deltic.ts --asset translator # deltic-translator-shim.wasm -// deno run … fetch-deltic.ts --asset embedder # deltic-embedder.mjs -// -// THE PIN lives here (TAG + per-asset sha256) and in the sibling -// import-map URLs (deno.json). `assertPinConsistency` fails loud if the -// two drift. Bumping: update TAG here and in deno.json, update the shas -// from the release's SHA256SUMS, delete deno.lock, and re-run -// `deno cache runner.ts fetch-deltic.ts` in this directory to regenerate -// it (commit the diff). - -const TAG = "pre-83fff30"; -const ASSETS: Record = { - translator: { - file: "deltic-translator-shim.wasm", - sha256: "6d02b363785593595a789d083cda0aebb1de790726718ccf543198354fa3870c", - }, - embedder: { - file: "deltic-embedder.mjs", - sha256: "b9ceb33c78abdaa4311f681c1388b14a3471f8a17ebd2dbf2dddd4a596df72c3", - }, -}; - -const HERE = new URL(".", import.meta.url); -const REPO_ROOT = new URL("../../", HERE); - -async function sha256Hex(bytes: Uint8Array): Promise { - const digest = await crypto.subtle.digest( - "SHA-256", - bytes as BufferSource, - ); - return Array.from(new Uint8Array(digest)) - .map((b) => b.toString(16).padStart(2, "0")) - .join(""); -} - -/** The one-pin-everywhere gate: every raw.githubusercontent URL in the - * sibling import map must reference TAG. */ -async function assertPinConsistency(): Promise { - const denoJson = await Deno.readTextFile(new URL("deno.json", HERE)); - const urls = denoJson.match(/https:\/\/raw\.githubusercontent\.com[^"]+/g) ?? []; - if (urls.length === 0) { - throw new Error("deno.json: no pinned deltic URLs found"); - } - for (const url of urls) { - if (!url.includes(`/lann/deltic/${TAG}/`)) { - throw new Error( - `pin drift: deno.json pins ${url}\nbut fetch-deltic.ts pins ${TAG}`, - ); - } - } -} - -async function main() { - const idx = Deno.args.indexOf("--asset"); - const which = idx >= 0 ? Deno.args[idx + 1] : undefined; - const asset = which !== undefined ? ASSETS[which] : undefined; - if (asset === undefined) { - console.error( - `usage: fetch-deltic.ts --asset <${Object.keys(ASSETS).join("|")}>`, - ); - Deno.exit(2); - } - - await assertPinConsistency(); - - const cacheDir = new URL(`target/deltic/${TAG}/`, REPO_ROOT); - const cached = new URL(asset.file, cacheDir); - try { - const bytes = await Deno.readFile(cached); - if (await sha256Hex(bytes) === asset.sha256) { - console.log(cached.pathname); - return; - } - console.error(`cached ${asset.file} has a stale digest; re-fetching`); - } catch { - // not cached yet - } - - const releaseUrl = - `https://github.com/lann/deltic/releases/download/${TAG}/${asset.file}`; - console.error(`fetching ${releaseUrl} …`); - const resp = await fetch(releaseUrl); - if (!resp.ok) { - throw new Error(`GET ${releaseUrl}: ${resp.status} ${resp.statusText}`); - } - const bytes = new Uint8Array(await resp.arrayBuffer()); - const got = await sha256Hex(bytes); - if (got !== asset.sha256) { - throw new Error( - `sha256 mismatch for ${asset.file}@${TAG}:\n want ${asset.sha256}\n got ${got}`, - ); - } - await Deno.mkdir(cacheDir, { recursive: true }); - await Deno.writeFile(cached, bytes); - console.log(cached.pathname); -} - -await main(); diff --git a/js/runner-deltic/runner.ts b/js/runner-deltic/runner.ts index 4882e8c..a33cad1 100644 --- a/js/runner-deltic/runner.ts +++ b/js/runner-deltic/runner.ts @@ -11,18 +11,24 @@ // // deno run --allow-read=target --config js/runner-deltic/deno.json \ // --frozen js/runner-deltic/runner.ts \ -// --translator [--jsonl] [--target NAME] +// [--translator ] [--jsonl] [--target NAME] // -// The deltic release pin lives in deno.json + fetch-deltic.ts (which -// see, for the bump procedure). +// The translator comes from the pinned @deltic/translator package through +// the module graph (permission-free: no net grant, no read grant for the +// asset). `--translator` stays as a documented escape hatch for driving an +// externally-sourced translator wasm; absent, the packaged one is used. +// +// The deltic pin lives in deno.json + deno.lock (which see, and README.md +// for the bump procedure). import { Translator } from "@deltic/runtime/shim"; +import { defaultTranslator } from "@deltic/translator"; import { runSuite } from "@deltic/ct-runner"; import { wasiShims } from "@deltic/wasi-shims"; interface Cli { suitePath: string; - translator: string; + translator?: string; jsonl: boolean; target: string; missing?: string[]; @@ -54,9 +60,9 @@ function parseArgs(argv: string[]): Cli { positional.push(a); } } - if (positional.length !== 1 || translator === undefined) { + if (positional.length !== 1) { console.error( - "usage: runner.ts --translator " + + "usage: runner.ts [--translator ] " + "[--jsonl] [--target NAME] [--missing f1,f2,...]", ); Deno.exit(2); @@ -107,7 +113,11 @@ function suiteNameFrom(path: string): string { async function main() { const cli = parseArgs(Deno.args); const componentBytes = await Deno.readFile(cli.suitePath); - const translator = await Translator.create(await Deno.readFile(cli.translator)); + // Packaged by default (loads through the module graph, no permissions); + // --translator drives an externally-sourced translator wasm instead. + const translator = cli.translator === undefined + ? await defaultTranslator() + : await Translator.create(await Deno.readFile(cli.translator)); const { plan, adapters } = translator.translate(componentBytes); const lines: string[] = []; diff --git a/js/runner-deltic/worker-main.mjs b/js/runner-deltic/worker-main.mjs index 3695096..64261c9 100644 --- a/js/runner-deltic/worker-main.mjs +++ b/js/runner-deltic/worker-main.mjs @@ -9,7 +9,7 @@ // across the boundary. The downstream pattern is a bundled worker entry: // // // worker-entry.ts — deno bundle --platform browser -// import * as deltic from "…/tools/release-bundle/entry.ts"; // raw URLs +// import * as deltic from "./browser-bundle-entry.ts"; // jsr:@deltic/* // import { workerMain } from "@polymorph/component-test-js/deltic-worker-main"; // import { configure, websocketImports } from "../../js/deltic/websocket.ts"; // workerMain({ diff --git a/js/viewer/deltic.mjs b/js/viewer/deltic.mjs index 233724e..86eed65 100644 --- a/js/viewer/deltic.mjs +++ b/js/viewer/deltic.mjs @@ -1,5 +1,6 @@ // Runtime-linked viewer engines (the jco replacement's Phase 4): the -// pinned deltic release assets are deployed beside the viewer by +// deltic browser assets (repo-built from the pinned JSR graph — see +// js/runner-deltic/README.md) are deployed beside the viewer by // `just viewer-build` (locally and on Pages alike — same relative // layout), and the aggregation component is instantiated at first use. // diff --git a/justfile b/justfile index 97abd00..d6c92e4 100644 --- a/justfile +++ b/justfile @@ -99,12 +99,88 @@ verify-compose: build diff -u expected/verify-pipeline-sample-fold.txt "$tmp/fold.txt" echo "verify-compose: output matches expected/ (incl. JSONL + cross-runner fold)" +# The one-version-everywhere gate for the deltic pin (successor to the +# retired fetch script's `assertPinConsistency`): every jsr:@deltic/* +# specifier in every deno.json, and every @deltic package the lock +# resolves, must name the SAME prerelease — one version names one +# upstream commit, and the browser assets are built from that same graph. +deltic-pin-gate: + #!/usr/bin/env bash + set -euo pipefail + configs=(js/runner-deltic/deno.json) + v=$(grep -ho 'jsr:@deltic/[a-z-]*@[^/"]*' "${configs[@]}" | sed 's/.*@//' | sort -u) + test -n "$v" || { echo "deltic pin gate: no jsr:@deltic specifiers found" >&2; exit 1; } + [ "$(printf '%s\n' "$v" | wc -l)" = 1 ] || { echo "deltic pin drift: $v" >&2; exit 1; } + python3 - "$v" js/runner-deltic/deno.lock <<'PY' + import json, sys + want, lock = sys.argv[1], json.load(open(sys.argv[2])) + bad = {k: r for k, r in lock.get("specifiers", {}).items() + if "@deltic/" in k and r != want} + bad.update({k: k for k in lock.get("jsr", {}) if k.startswith("@deltic/") + and not k.endswith("@" + want)}) + if bad: + sys.exit(f"deltic lock drift (want {want}): {sorted(bad)}") + PY + echo "deltic pin gate: all @deltic packages pinned to $v" + +# The deltic browser-leg assets, built from the pinned JSR graph (no +# network fetch, no sha bookkeeping — deno.lock carries JSR package +# integrity and --frozen enforces it): +# +# target/deltic-browser/deltic-embedder.mjs bundled from +# js/runner-deltic/browser-bundle-entry.ts (embedder API + +# Translator + ct-runner glue + wasi shims, one platform-neutral +# ES module — what the browser worker and the node selftest load) +# target/deltic-browser/deltic-translator-shim.wasm the translator +# asset packaged in @deltic/translator, copied out of the +# lock-pinned module cache (the Deno runner leg needs no copy: it +# loads the packaged translator through the module graph) +# +# The directory is version-free on purpose: the lock owns versioning. +deltic-assets: deltic-pin-gate + #!/usr/bin/env bash + set -euo pipefail + out=target/deltic-browser + mkdir -p "$out" + deno bundle --config js/runner-deltic/deno.json --frozen --platform browser \ + -o "$out/deltic-embedder.mjs" js/runner-deltic/browser-bundle-entry.ts + tmp=$(mktemp -d); trap 'rm -rf "$tmp"' EXIT + deno info --json --config js/runner-deltic/deno.json --frozen @deltic/translator \ + > "$tmp/info.json" + pin=$(grep -o 'jsr:@deltic/runtime@[^/"]*' js/runner-deltic/deno.json | head -1 | sed 's/.*@//') + python3 - "$tmp/info.json" "$out/deltic-translator-shim.wasm" "$pin" <<'PY' + import json, sys + graph = json.load(open(sys.argv[1])) + want = sys.argv[3] + mods = [m for m in graph["modules"] if "/@deltic/" in m.get("specifier", "")] + bad = {m["specifier"] for m in mods if want not in m["specifier"]} + if bad: + sys.exit(f"pin drift in translator graph (expected {want}): {bad}") + asset = next(m for m in mods if m["specifier"].endswith("/translator_shim.wasm")) + # CONTRACT: the migration contract copies the cache file wholesale, but + # Deno 2.9.5 stores remote modules as body + a "\n// denoCacheMetadata={...}" + # trailer; copying it verbatim yields a wasm that fails to compile + # ("section out of order"). Take exactly the module's own byte length + # (deno info's `size`, == the response content-length) and assert that + # anything past it is only that trailer. + blob = open(asset["local"], "rb").read() + body, rest = blob[: asset["size"]], blob[asset["size"] :] + if not body.startswith(b"\0asm"): + sys.exit("translator asset is not a wasm module") + if rest and not rest.lstrip(b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\r ").startswith(b"// denoCacheMetadata="): + sys.exit("unexpected trailing bytes in cached translator asset") + open(sys.argv[2], "wb").write(body) + PY + # Path 3: deltic-deno runner (runner-is-provider, like Path 3, but no # transpile step, no generated tree, and no engine flag — deltic is a # runtime linker; the contract's async exports run on the callback ABI -# under stock Deno). Pinned to a deltic release by -# js/runner-deltic/{deno.json,fetch-deltic.ts}, with deno.lock enforced -# via --frozen. Tag scheduling comes from the suite's own embedded +# under stock Deno). Pinned to exact deltic JSR prereleases by +# js/runner-deltic/deno.json, with deno.lock enforced via --frozen and +# agreement asserted by deltic-pin-gate. The Deno leg's translator comes +# from the packaged @deltic/translator through the module graph; the +# browser/node legs use the repo-built assets (`just deltic-assets`). +# Tag scheduling comes from the suite's own embedded # inventory (deltic#25): the fixture leg runs --missing hsm exactly like # Paths 1/4 and schedules the hsm case out as not-applicable; the sample # legs reuse Path 2/3's human golden and Path 2/4's fold golden. The @@ -112,17 +188,14 @@ verify-compose: build # engine.mjs + the shared harness.mjs case loop) over the pinned embedder # bundle under plain node — no --experimental-wasm-jspi: the callback ABI # needs no engine flag, which is the browser-leg premise. -verify-deltic: build +verify-deltic: build deltic-assets #!/usr/bin/env bash set -euo pipefail tmp=$(mktemp -d); trap 'rm -rf "$tmp"' EXIT - fetch() { deno run --allow-read=js/runner-deltic,target --allow-write=target \ - --allow-net=github.com,objects.githubusercontent.com,release-assets.githubusercontent.com \ - js/runner-deltic/fetch-deltic.ts --asset "$1"; } - translator=$(fetch translator) - bundle=$(fetch embedder) + translator=target/deltic-browser/deltic-translator-shim.wasm + bundle=target/deltic-browser/deltic-embedder.mjs run() { deno run --allow-read=target --config js/runner-deltic/deno.json --frozen \ - js/runner-deltic/runner.ts "$@" --translator "$translator"; } + js/runner-deltic/runner.ts "$@"; } norm() { sed -E -e 's/"artifact-sha256":"[0-9a-f]{64}"/"artifact-sha256":""/' \ -e 's/,"duration-ms":[0-9]+//g'; } fold() { cargo run -q -p component-test-cli -- fold "$@"; } @@ -245,17 +318,13 @@ emit-demo: build # no transpile step) and the demo suites (component wasm, verbatim), # plus the pinned deltic assets copied beside the viewer so local serve # and Pages share one relative layout (js/viewer/deltic.mjs). -viewer-build: build +viewer-build: build deltic-assets #!/usr/bin/env bash set -euo pipefail cargo build --release --target wasm32-wasip2 -p viewer-aggregate - fetch() { deno run --allow-read=js/runner-deltic,target --allow-write=target \ - --allow-net=github.com,objects.githubusercontent.com,release-assets.githubusercontent.com \ - js/runner-deltic/fetch-deltic.ts --asset "$1"; } - translator=$(fetch translator) - bundle=$(fetch embedder) mkdir -p js/viewer/deltic js/viewer/generated js/viewer/suite - cp "$translator" "$bundle" js/viewer/deltic/ + cp target/deltic-browser/deltic-translator-shim.wasm \ + target/deltic-browser/deltic-embedder.mjs js/viewer/deltic/ cp {{release_dir}}/viewer_aggregate.wasm js/viewer/generated/viewer-aggregate.wasm cp {{release_dir}}/sample_suite.wasm {{release_dir}}/fixture_suite.wasm js/viewer/suite/