Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions .machine_readable/6a2/META.a2ml
Original file line number Diff line number Diff line change
Expand Up @@ -1192,3 +1192,71 @@ references = [
"docs/RESCRIPT-ELIMINATION.adoc (#229 canonical map; Tier-3 ESC-01)",
"META.a2ml [[adr]] ADR-012 (grammar changes are correctness assertions)",
]

[[adr]]
id = "ADR-019"
status = "accepted"
date = "2026-05-19"
title = "Compiler distribution: GitHub Releases binaries + thin Deno/JSR shim (#260)"
context = """
INT-04 (#181) is "publish compiler + runtime". The runtime JS packages
are JSR-publishable and that path is done (affinescript#261). The
*compiler* is a native OCaml binary — it is NOT a JSR or npm package,
so "publish the compiler" needed a distribution strategy. This gates
INT-10 (`affinescript-lsp` distribution, which "waits on a published
compiler"). The fork was escalated (issue #260; AskUserQuestion
2026-05-19) over four options: (1) GitHub Releases binaries, (2)
Guix/Nix channel, (3) thin JSR/npm shim, (4) Releases + shim. The
owner chose (4).
"""
decision = """
Dual-channel, Releases-canonical:

- *Canonical artifact.* Extend the existing `release.yml` (`v*` tags)
to build per-platform compiler binaries (Linux x86_64 first;
macOS/Windows as the build matrix allows) and attach them to the
GitHub Release together with a `SHA256SUMS` manifest. Releases are
the single source of truth; Guix/Nix and any npm tail become
*additive fetch-derivations over the same artifact* later (NOT in
this ADR's slices) — no second producer of the binary.
- *Ergonomic front door.* A thin Deno/JSR package
`@hyperpolymath/affinescript` (Deno-first per CLAUDE.md; no OCaml
source shipped) whose setup step downloads the host-platform binary
from the pinned Release, verifies it against the `SHA256SUMS`
checksum *embedded in that shim version*, caches it, and execs it.
HTTPS-only; no secrets in the shim; provenance = this repo's own
release workflow. Each shim version pins exactly one compiler
version+checksum (supply-chain: no floating fetch).
- *Consumer.* INT-10 `affinescript-lsp` resolves the compiler via the
shim (`deno add` ergonomics) — this is what unblocks it.
- npm tail: only if/when an npm-native consumer needs it, mirroring
the owner-sanctioned affine-vscode npm exception; deferred, not in
scope here.

Staged (ledger #260 / INT-10; each a gated PR):
- S1 (this): ADR-019 + plan; file INT-10. No code.
- S2: `release.yml` per-platform binary + `SHA256SUMS` matrix.
- S3: the `@hyperpolymath/affinescript` shim package (download +
checksum-verify + cache + exec) + its tests; publish is owner-gated
via the existing manual JSR workflow (like INT-04).
- S4: wire INT-10 `affinescript-lsp` onto the shim.
"""
consequences = """
- One-way: fixes the install contract (Releases artifact name/layout +
shim package name). Reversible per-slice; Releases-canonical keeps
Guix/Nix/npm strictly additive.
- INT-10 (`affinescript-lsp` distribution) is unblocked once S2+S3
land; filed now.
- Supply chain: every shim release pins one checksummed binary; no
floating download.
- This decision is settled; do not reopen without amending this ADR.
Ledger #260 / INT-10 in docs/TECH-DEBT.adoc.
"""
references = [
"https://github.com/hyperpolymath/affinescript/issues/260",
"https://github.com/hyperpolymath/affinescript/issues/181",
".github/workflows/release.yml",
".github/workflows/publish-jsr.yml (INT-04; owner-gated publish)",
"docs/PACKAGING.adoc (INT-04; the JS-package half)",
"docs/specs/SETTLED-DECISIONS.adoc (ADR-019 section)",
]
5 changes: 3 additions & 2 deletions docs/ECOSYSTEM.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,9 @@ corrected. INT-02 dep cleared. Runtime BLOCKED by #255 (wasm
loop-codegen defect, pre-existing)
|INT-09 |`affinescript-cadre` router/navigation runtime |ledger-only
|planned (blocked by INT-07)
|INT-10 |LSP distribution (`affinescript-lsp`) |ledger-only |planned
(blocked by INT-04)
|INT-10 |LSP distribution (`affinescript-lsp`) |#282 |unblocked —
distribution decided (ADR-019: Releases + thin Deno/JSR shim, #260).
Consumes the shim once #260 S2/S3 land
|INT-11 |Browser host parity (DOM loader + reconciler end-to-end) |
ledger-only |planned (blocked by INT-02/08)
|INT-12 |typed-wasm convergence: AffineScript-emitted fixtures into the
Expand Down
4 changes: 3 additions & 1 deletion docs/TECH-DEBT.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,9 @@ compiler-emitted xmod wasm (closes INT-01↔INT-02). Unblocks INT-05/08/11
Component-Model re-target, staged S1..S6); S3+ hard-gated on S2
toolchain (`wasm-tools`/`wasm-component-ld`)
|INT-04 |Publish to JSR/npm |S2 |#181 packaging READY (dry-run green,
manual workflow); owner-gated publish; compiler-binary = #260
manual workflow); JSR publish authorised + dispatched (owner go
2026-05-19); compiler-binary distribution decided = **ADR-019**
(#260, Releases + thin Deno/JSR shim, staged S1..S4) — unblocks INT-10
|INT-07 |`affinescript-tea` runtime |S2 |#182 runtime + run loop shipped
(TeaApp/parseTeaLayout, Linear-msg enforced); INT-01 cleared (#253)
|INT-08 |DOM reconciler |S2 |#183 implemented + compiles; `.as`→`.affine`
Expand Down
33 changes: 33 additions & 0 deletions docs/specs/SETTLED-DECISIONS.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -409,3 +409,36 @@ parts of `burble`) port under this doctrine; per-file execution is the
This decision is settled; do not reopen without amending the ADR. Full
ADR in `.machine_readable/6a2/META.a2ml` (ADR-018); #229 canonical map in
`docs/RESCRIPT-ELIMINATION.adoc`; escalation issue #245.

== Compiler Distribution: GitHub Releases Binaries + Thin Deno/JSR Shim (ADR-019)

INT-04 (#181) is "publish compiler + runtime". The runtime JS packages
are JSR-publishable and shipped (#261); the *compiler* is a native
OCaml binary — not a JSR/npm package — so its distribution was an
escalated one-way-door fork (issue #260, AskUserQuestion 2026-05-19)
over Releases-binaries / Guix-Nix / JSR-shim / combination. The owner
chose the *combination*.

Decision: *Releases-canonical, dual-channel*. The existing
`release.yml` (`v*` tags) is extended to build per-platform compiler
binaries + a `SHA256SUMS` manifest attached to the GitHub Release (the
single source of truth — Guix/Nix and any npm tail are additive
fetch-derivations over it later, not separate producers). A thin
Deno/JSR package `@hyperpolymath/affinescript` is the ergonomic front
door: it downloads the host-platform binary from the pinned Release,
verifies it against the `SHA256SUMS` checksum embedded in that shim
version, caches and execs it (HTTPS-only, no secrets, one
version+checksum pinned per shim release — no floating fetch).
`affinescript-lsp` (INT-10) consumes the shim, which is what unblocks
INT-10. An npm tail is deferred (only if an npm-native consumer needs
it, mirroring the affine-vscode exception).

Staged (ledger #260 / INT-10): *S1* this ADR + plan + file INT-10 (no
code); *S2* `release.yml` per-platform binary + `SHA256SUMS` matrix;
*S3* the shim package (download + checksum-verify + cache + exec) +
tests, publish owner-gated via the existing manual JSR workflow; *S4*
wire INT-10 `affinescript-lsp` onto the shim.

This decision is settled; do not reopen without amending the ADR. Full
ADR in `.machine_readable/6a2/META.a2ml` (ADR-019); ledger #260 /
INT-10 in `docs/TECH-DEBT.adoc`.
Loading