- Status
-
Accepted
- Date
-
2026-05-19 (accepted); implementation S1–S4 landed 2026-05-20
- Issue
-
INT-04 #260 (split from #181)
- Series
-
Settled-decisions ledger; companion entry in
.machine_readable/6a2/META.a2ml id="ADR-019"; narrative indocs/specs/SETTLED-DECISIONS.adoc§"Compiler Distribution".
INT-04 (#181) is "publish compiler + runtime". The two halves have very different shapes:
-
The runtime JS packages (
@hyperpolymath/affine-js,@hyperpolymath/affinescript-tea) are ordinary JSR/npm packages — their publish path is bounded packaging-prep (docs/PACKAGING.adoc) and was already ready/independent of this decision. -
The compiler is a native OCaml binary. It is not a JSR/npm package, so "publish the compiler" has no off-the-shelf answer. How consumers — and in particular
affinescript-lsp(INT-10) — install it is a one-way-door contract: it sets the install surface, the checksum/trust story, and the LSP’s compiler-resolution path.
This was escalated as a design fork (issue #260, AskUserQuestion 2026-05-19) rather than guessed, because it is irreversible-ish and outside the packaging-prep scope.
The fork presented four options:
(1) GitHub Releases binaries. Per-platform artifacts via the existing
release.yml (v* tags) + an install script / fetch-pin.
(2) Guix/Nix channel. Aligns with the repo’s primary packaging
(guix.scm / flake.nix); reproducible, but a narrower audience and no
deno/npm ergonomics for the LSP-installer consumers.
(3) Thin JSR/npm shim. A small package that, on first run, downloads a
pinned, checksummed prebuilt binary and execs it — deno/npm
ergonomics without shipping OCaml source.
(4) Combination of the above.
The owner chose the combination, with GitHub Releases as the single canonical artifact source and a thin Deno/JSR shim as the ergonomic front door:
-
Canonical artifact.
.github/workflows/release.yml, on av*tag, builds per-platform compiler binaries and aSHA256SUMSmanifest, both attached to the GitHub Release. The Release is the one source of truth; Guix/Nix and any later npm tail are additive fetch-derivations over it, not separate producers. -
Ergonomic front door. A thin Deno/JSR package
@hyperpolymath/affinescriptdownloads the host-platform binary from the pinned Release, verifies it against theSHA256SUMSchecksum embedded in that shim version, then caches and execs it. HTTPS-only, no secrets, one version+checksum pinned per shim release (no floating fetch). -
LSP path.
affinescript-lsp(INT-10) resolves the compiler viaAFFINESCRIPT_COMPILER→affinescriptonPATH→ the@hyperpolymath/affinescriptshim. Consuming the shim is what unblocks INT-10; the LSP does no bespoke bundling. -
npm tail deferred. An npm publish is added only if an npm-native consumer needs it, mirroring the
affine-vscoderuntime exception. It is not wired by this ADR.
Tracked in docs/TECH-DEBT.adoc (INT-04 / INT-10); all four stages have
landed:
| Stage | Content | Status |
|---|---|---|
S1 |
This ADR + plan; file INT-10. No code. |
DONE |
S2 |
|
DONE (#283/#284/#285) |
S3 |
The shim package — download + checksum-verify + cache + exec + tests; publish owner-gated via the existing manual JSR workflow |
DONE |
S4 |
Wire INT-10 |
DONE (#282) |
First JSR publish landed 2026-05-20: @hyperpolymath/affinescript@0.1.2
LIVE (cross-runtime Deno + Bun + Node, MPL-2.0, sibling .d.ts for
JSR fast-check). The shim pins all three v0.1.1 binaries by SHA256, so the
resolution path executes end-to-end. Compiler version-string drift was fixed
in lock-step via lib/version.ml (single source of truth) + a release.yml
tag-time bake step (#297/#300).
-
The install contract is Releases-first. Renaming the
SHA256SUMSmanifest or the per-platform asset names is an ABI change for every shim version and for Guix/Nix derivations downstream — do not rename without amending this ADR and the shim’s pinned spec. -
Browsers and Cloudflare Workers are out of scope for the shim by construction (fetch → save to disk → exec a native binary cannot run in a sandboxed JS runtime). The shim’s runtime-compatibility matrix is therefore Deno ✅ / Bun ✅ / Node ✅ / Workers ❌ / Browsers ❌ (see
.claude/CLAUDE.mdRuntime Exemptions). -
Reproducible-build consumers are served by the additive Guix/Nix derivations layered over the same Release artifact, not by a competing artifact source.
-
Issue: #260 (INT-04 compiler distribution), split from #181.
-
Unblocks: INT-10 #282 (
affinescript-lspdistribution). -
docs/specs/SETTLED-DECISIONS.adoc§"Compiler Distribution: GitHub Releases Binaries + Thin Deno/JSR Shim (ADR-019)" — the narrative twin of this record. -
docs/PACKAGING.adoc§"The compiler itself — decided (ADR-019 / #260)". -
docs/TECH-DEBT.adocINT-04 / INT-10 rows. -
.machine_readable/6a2/META.a2ml id="ADR-019"— the machine record. -
.github/workflows/release.yml(S2 producer),.github/workflows/publish-jsr.yml(owner-gated shim publish),packages/affinescript-cli/(the shim).