Skip to content

Consume deltic from JSR: packaged translator, no fetch step - #45

Merged
lann merged 2 commits into
mainfrom
jsr-deltic-packages
Aug 11, 2026
Merged

Consume deltic from JSR: packaged translator, no fetch step#45
lann merged 2 commits into
mainfrom
jsr-deltic-packages

Conversation

@lann

@lann lann commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

The follow-up ruling flagged in #43: deltic consumption moves from raw.githubusercontent URLs + the sha-pinned release-asset fetch to the JSR prereleases deltic now publishes per green commit (0.1.0-pre.g<shorthash>, same hash as the GitHub release).

What this buys

  • @deltic/translator ships the translator wasm inside the package at the same version as the runtime, so the plan-format coupling that fetch-translator.ts existed to police is now self-consistent per graph by construction. The fetch step, the sha256 bookkeeping, the target/deltic/ cache, and the --allow-net grants all retire; on Deno the translator loads through the module graph permission-free.
  • The pin story collapses to: two deno.jsons carrying the same JSR versions + their lockfiles (--frozen). The residual cross-config convention (one deltic version repo-wide) is asserted by the exam-deltic recipe — the natural fail-loud point now that fetch-translator.ts's gate is gone.
  • The ping demo's raw-URL translate-CLI invocation becomes a ~20-line shared translate.ts (defaultTranslator() + Translator.translateRaw), and the spikes' browser harnesses use it too: all three browser surfaces now ride the A4 envelope path — component + envelope fetched, no translator on any page, and the ?translator= query-param plumbing is deleted.
  • minimumDependencyAge exempts jsr:@deltic/* (per deltic's consumption README) so same-day prerelease bumps resolve; every other dependency keeps Deno's default 24-hour supply-chain gate.

Not changed: the sibling host modules still come from the .deps checkouts pinned by setup.sh; the deltic version itself stays 0.1.0-pre.ga67ee83 (same commit #43 pinned by tag).

Gates (all green): just exam-deltic 5/5 incl. the new pin assert; relay-ws run.sh + browser-test (phase-2 echo p50 550 µs); blobs run.sh + browser-test (phase-2 fetch 6.36 MiB/s); ping-demo build.sh + full Playwright suite; deno check across host-deltic and all three experiments; just check.

deltic publishes exactly-pinned JSR prereleases per green upstream
commit (0.1.0-pre.g<shorthash>), with @deltic/translator shipping the
translator wasm for the same commit — the runtime/translator
plan-format coupling is self-consistent inside each graph by
construction. That dissolves most of the raw-URL pin architecture:

- import maps move to jsr:@deltic/{runtime,wasi-shims,translator}
  versions; deno.lock carries integrity, --frozen enforces it;
  minimumDependencyAge exempts jsr:@deltic/* from Deno's default
  supply-chain age gate so same-day prereleases resolve (everything
  else keeps the default);
- fetch-translator.ts is retired: host-deltic's harness and the spike
  drivers load @deltic/translator's packaged asset through the module
  graph (permission-free on Deno — no --allow-net, no sha bookkeeping,
  no target/deltic cache); what remains of the one-pin-repo-wide gate
  is an equality assert across the two deno configs in the exam-deltic
  recipe;
- the raw-URL translate-CLI invocation in ping-demo's build.sh becomes
  a small shared script (experiments/iroh-relay-ws/host/translate.ts:
  defaultTranslator + Translator.translateRaw), which also lets the
  spikes' browser harnesses pre-translate their guests — all three
  browser surfaces now ride the A4 envelope path, the ?translator=
  query-param plumbing is gone, and no translator ever ships to a
  browser.

Gates: just exam-deltic — EXAM PASS (5/5, pin assert green);
iroh-relay-ws run.sh + browser-test (phase 2 p50 550us);
iroh-blobs run.sh + browser-test (phase 2 6.36 MiB/s);
ping-demo build.sh + Playwright suite PASS; deno checks green across
host-deltic and all three experiments; just check green.

@lann lann left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed with independent verification (details below). Direction is right and matches deltic's consumption README exactly; one small real bug and one gate-coverage suggestion before merge, two nits.

Bug (fresh checkout): the browser harnesses write the envelope into dist/ before anything creates it. Both browser-test.mjs files run translateGuest()translate.tsDeno.writeTextFile(<host>/dist/<guest>.plan.json) before bundleEntry(). dist/ is gitignored, Deno.writeTextFile does not create parent dirs (verified: NotFound), and in the old order the first dist/ writer was deno bundle, which does create the output dir (verified). So on a fresh clone the browser test dies at the translate step in both spikes; existing workspaces don't see it because dist/ survives from earlier runs. Cheapest robust fix: await Deno.mkdir(dirname(output), { recursive: true }) in translate.ts — it covers every caller including future ones (ping-demo's build.sh is unaffected only because it happens to mkdir -p "$SITE" first).

Gate suggestion: assert one version across all @deltic/* pins, not just @deltic/runtime across the two configs. The retired assertPinConsistency checked every deltic URL in each file against THE tag; the new exam-deltic grep only compares @deltic/runtime between the two deno.jsons. A bump that moves runtime+wasi-shims but forgets @deltic/translator (or vice versa) passes the gate and lands in exactly the territory this PR calls impossible "by construction": translator wasm from one commit, runtime from another — plan-format skew, or two runtime copies in the graph (WitError identity break), depending on how the ~0.1.0-pre.g<hash> range dedupes (hash prereleases are unordered, so dedupe direction is luck). Self-consistency is by construction only when the import map agrees with itself. One-liner that closes the whole class:

v=$(grep -ho 'jsr:@deltic/[a-z-]*@[^/"]*' host-deltic/deno.json experiments/iroh-relay-ws/host/deno.json | sed 's/.*@//' | sort -u)
[ "$(printf '%s\n' "$v" | wc -l)" = 1 ] || { echo "deltic pin drift: $v" >&2; exit 1; }

(Tested against the branch: yields exactly 0.1.0-pre.ga67ee83; the minimumDependencyAge exclude jsr:@deltic/* doesn't match the pattern.)

Nits

  • host-deltic/deno.lock still carries 48 stale pre-58b2404 remote entries (pre-existing; nothing references them, --frozen tolerates extras). The README's own bump procedure — delete both locks, regenerate — would drop them; worth doing while touching the locks anyway.
  • The browser-test translate step widened from scoped grants to bare --allow-read --allow-write. Retiring --allow-net is the win, but read/write could stay scoped (--allow-read=<ROOT> --allow-write=<host>/dist). Dev harness, so nit.

Verified during review

  • Consumption pattern matches deltic README §"Consuming the unstable prereleases" verbatim (exact 0.1.0-pre.g<shorthash> pins, the minimumDependencyAge stanza, packaged defaultTranslator()); CI pins Deno 2.9.5, satisfying the ≥2.9 wildcard-exclude requirement.
  • Reproduced the age-gate necessity empirically: unqualified deno info jsr:@deltic/translator@0.1.0-pre.ga67ee83 is blocked by the default 24 h gate today; the version exists on JSR (as do runtime/wasi-shims at the same hash, per lock integrity + --frozen CI).
  • defaultTranslator() / Translator.translateRaw() verified at a67ee83, including the Deno permission-free module-graph load path claimed in the body; artifactsFrom pre-exists in harness.ts (ping-demo already rides it), so the browser entries' import is sound.
  • No leftover fetch-translator / DELTIC_TRANSLATOR / raw-URL deltic references on the branch outside lockfiles.
  • Merge semantics vs. main's #44/#32 (branch is 2 merges behind): no new callers of the deleted machinery landed on main, and main's newer websocket pin (f8fdf66) still imports only @deltic/runtime/embedder, which both configs map — textually and semantically clean.
  • CI has no deno-side gate (just check = fmt/clippy/wit/test), so I ran the Deno graphs independently at the branch's .deps pins: deno check green for host-deltic src and all three experiments (run/browser-entry/translate/harness, blobs host, ping-demo demo.ts).

LGTM once the dist/ fix lands; the gate strengthening can ride the same commit or a follow-up.

@lann
lann enabled auto-merge August 11, 2026 03:22
@lann

lann commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator Author

Pushed the review fixes directly (fc713d1) rather than waiting — all three actionable items from the review, plus a correction to the review itself:

What the commit does

  • translate.ts creates the output dir (Deno.mkdir(dirname(output), { recursive: true })): the browser harnesses write the envelope into gitignored dist/ before deno bundle (the old first-creator) runs, so fresh checkouts died at the translate step. Verified by running both spikes' browser tests in a worktree that never had a dist/.
  • The exam-deltic drift gate now asserts one version across every jsr:@deltic/* pin in both configs (was: @deltic/runtime only, cross-config). Negative-tested: a translator-only bump trips it; aligned configs pass.
  • The browser-test translate step's grants are scoped again (--allow-read=<ROOT> --allow-write=<host>/dist), matching the pre-Consume deltic from JSR: packaged translator, no fetch step #45 posture minus the retired net grants.

Review correction — the "48 stale lock entries" nit was wrong. Deleting and regenerating host-deltic/deno.lock reproduces those pre-58b2404 remote entries byte-identically: they are load-bearing. deno info on the run-endpoint graph shows why — .deps/webcrypto/js/deltic/src/{errors,platform}.ts import @deltic/runtime/embedder as a bare specifier, but the sibling's own package-shaped deno.json maps it to the raw pre-58b2404 URL, and that nested mapping wins for the package's files. So the graph carries two embedder copies (jsr ga67ee83 + raw pre-58b2404), i.e. the exact instanceof WitError identity split the MODULE-IDENTITY comments warn about, latent on any webcrypto error path. This pre-dates #45 (main's lock carries both pre-58b2404 and pre-a67ee83 remote sections — same split, older versions) and is not fixable here: it converges when WEBCRYPTO_PIN (and friends) bump to sibling revs that consume deltic from JSR, at which point the nested config maps to the same jsr: package as the host's and Deno dedupes to one module. Those sibling migrations are now in review (polymorph-webcrypto#364, polymorph-websocket#46, polymorph-webrtc-datachannels#153, polymorph-test#84, polymorph-tls#43 — webcrypto/websocket/test/tls CI fully green); a .deps pin-bump follow-up here closes the loop.

Gates re-run on the branch (all green): just exam-deltic 5/5 (pin gate inline); relay-ws browser-test from a fresh checkout (phase-2 echo p50 570 µs); blobs browser-test from a fresh checkout (phase-2 fetch 6.15 MiB/s); ping-demo build.sh; deno check --frozen across host-deltic and all three experiments. Lock untouched (regen was a no-op, as above).

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