Skip to content

Latest commit

 

History

History
446 lines (421 loc) · 24.4 KB

File metadata and controls

446 lines (421 loc) · 24.4 KB

AffineScript Coordination Ledger (TECH-DEBT)

Important

This is the durable coordination index for the AffineScript doc-truthing
ecosystem epic (issue #175). Sub-issues are the work units; this ledger is the critical path and the shared state across sessions/bots. ID classes: DOC (documentation truthing), CORE (compiler soundness/completeness), STDLIB, INT (ecosystem integration), SAT (satellite repos). Severity: S1 = substrate/blocking, S2 = important, S3 = polish. Reconstructed and made authoritative 2026-05-19 (it was cited by #175–183 / #228 / #177 but never committed). For the spine + contract see ECOSYSTEM.adoc; for readiness see CAPABILITY-MATRIX.adoc.

Critical path (read first)

Stage A  CLOSED ───────────────────────────────────────────────┐
Stage B  CLOSED (#215; residual conflicts = ADR-012 won't-fix)  │
Stage C  CLOSED 2026-05-18 (#128/#135 stdlib AOT)               │
                                                                 ▼
Stage D  ACTIVE ── CORE-01 (#177)  ─┐                            (base lang
         ├─ INT-01 (#178) ──────────┼─ substrate, S1            complete)
         ├─ INT-02 (#179) ──┐       │
         ├─ INT-03 (#180)   │       │
         └─ INT-04 (#181) ◄─┘ (◄ INT-01)                         │
            ADR-014 (#228)  ── estate port unblocker, S1         │
                                                                 ▼
Stage E  planned ── typed-wasm convergence hardening
         (#234, #235, #225/#160 line, INT-12) ──► stable multi-producer ABI

The mandate’s order of operations: CORE-01 first (the one named base-language soundness gap; user decision 2026-05-19), then the INT substrate, then Stage E.

Section A — DOC (documentation truthing)

Tracks issue #176. Authoritative status lives in CAPABILITY-MATRIX.adoc; this section keeps it from re-drifting.

ID Item Status

DOC-01

CAPABILITY-MATRIX.adoc exists and overrides all other status docs

DONE 2026-05-19 (this PR)

DOC-02

ECOSYSTEM.adoc — spine + AS↔typed-wasm contract + satellites
INT-01..12

DONE 2026-05-19 (this PR)

DOC-03

TECH-DEBT.adoc — this ledger

DONE 2026-05-19 (this PR)

DOC-04

Authoritative banners on README/BACKEND-IMPLEMENTATION/ COMPILER-CAPABILITIES/ALPHA-1-RELEASE-NOTES

DONE in tree 2026-05-21 (banners present on all four; README internal drift on lines 25/614 also fixed — pointed both at CAPABILITY-MATRIX). MONITOR posture stays live via DOC-08/09

DOC-05

STATE.a2ml drift flagged (it mirrors, does not lead)

DONE in tree 2026-05-21 (authoritative-status-doc + drift-flag keys present in .machine_readable/6a2/STATE.a2ml; README "Documentation" section now also labels STATE.a2ml as the mirror)

DOC-06

ROADMAP.adoc Ecosystem Integration Track (INT-01..12) cross-links this ledger

DONE in tree 2026-05-21 (ROADMAP.adoc §"Status & contract" cross-links CAPABILITY-MATRIX + TECH-DEBT + ECOSYSTEM and names the INT-01..12 track)

DOC-07

Stage A–E definitions authoritative (were never committed)

DONE 2026-05-19 (ECOSYSTEM.adoc §The spine)

DOC-08

MONITOR rule: reject backend-breadth over-claims

DONE (Hypatia/ gitbot DOC-FORMAT)

DOC-09

MONITOR rule: reject "production-ready"/stdlib-% over-claims

DONE

DOC-10

docs/standards/TESTING.adoc — authoritative test taxonomy (alcotest unit / alcotest E2E / fixture / golden / smoke / microbench), PR-level expectations, deferred-regression-test protocol; replaces stale docs/guides/TESTING-REPORT.adoc (2025-12-29 snapshot, 47/27 pass rate, contradicted by live gate since early 2026 — retired in-place with redirect)

DONE 2026-05-23

DOC-11

docs/standards/PANIC-ATTACK.adoc — SOP for the estate compliance scanner (disposition vocabulary fix/accept/suppress/defer; standing- suppression record format; weekly cron via .github/workflows/panic-attack.yml, ad-hoc via just panic, pre-release per RELEASE.md)

DONE 2026-05-23

DOC-12

Bench harness + coverage instrumentation — bench/ dune stanza under @bench alias (lex / parse / typecheck+quantity / codegen-wasm sweeps); CI jobs bench-visibility + coverage-visibility upload artifacts; bisect_ppx added as with-test depend; just bench / just bench-record / just coverage recipes. Visibility-only — no merge-blocking gate today (ratchet prerequisite: calibrated baseline).

DONE 2026-05-23

DOC-13

docs/specs/TYPED-WASM-INTERFACE.adoc (+ .a2ml machine companion) — formal spec of the AS↔typed-wasm interface v1 (carrier binary layout, enforced levels L7+L10+L13, producer/ consumer machinery file pointers, CLI surface, test coverage, multi-producer responsibilities, deliberate non-features NF-001..NF-005). Supersedes the §"actual AS↔typed-wasm contract" paragraph in ECOSYSTEM.adoc as the source of truth.

DONE 2026-05-23

DOC-14

docs/specs/TYPED-WASM-ROADMAP.adoc (+ .a2ml) — widening roadmap making typed-wasm a natural and optimal target. Tranches A (ergonomics) / B (schema hygiene; ADR-020 proposed) / C (compiler-side foundations for L1–6 / L14–16) / D (multi-producer ABI; ADR-021 proposed) / E (cross-compat closure). Per-tranche work-items, blockers, recommended sequencing.

DONE 2026-05-23

DOC-15

ADR-020 (PROPOSED): ownership-section schema versioning (0xAF sentinel + u8 version). ADR-021 (PROPOSED): multi-producer ABI coordination model (four axes: spec authority / coordinated landing / test parity / conflict resolution). Both filed in META.a2ml; ADR-020 lands first as the first test of ADR-021’s protocol. Both require owner ratification.

PROPOSED 2026-05-23

DOC-16

In-repo enforcement of the DOC-04/05 truthing invariant — tools/check-doc-truthing.sh (toolchain-free bash) fails if any over-claiming doc loses its CAPABILITY-MATRIX.adoc banner, if the matrix stops self-declaring primacy or loses its "What AffineScript is NOT" section, or if STATE.a2ml drops its mirror keys. Wired into just check (the guard recipe) and CI (ci.yml build job). Converts the DOC-08/09 MONITOR posture from external-bot-only to a first-class in-repo gate.

DONE 2026-05-30

MONITOR enforcement (DOC-08/09): any PR re-introducing backend-breadth, "production-ready", or stdlib-percentage over-claims must be rejected. As of DOC-16 (2026-05-30) the banner/mirror half of this is enforced in-repo by tools/check-doc-truthing.sh; the external Hypatia/gitbot DOC rules remain the catch-all for novel over-claim phrasings.

Section B — CORE (compiler soundness / completeness)

ID Item Sev Status

CORE-01

Borrow-checker Phase-3 — borrow-graph validation. Part 1 LANDED (PR 240, Refs #177, gate 263/263): BorrowOutlivesOwner emitted; shared-XOR-exclusive enforced at use sites (UseWhileExclusivelyBorrowed); ownership derived from the param type (TyOwn/TyRef/TyMut) — owned/ref/mut discipline now enforced from real parsed source (closed a latent hole); call-arg borrows temporary; ref-binding graph tracked. Part 2 — return-escape LANDED (Refs #177, gate 271→274): return e (or fn-tail) whose value is a reference rooted at a callee-owned binding (local or by-value/own param) is now BorrowOutlivesOwner (pt1 only saw block tails — return r slipped through); ref/mut params are caller-owned and not flagged (no over-rejection; full stdlib AOT green). 3 hermetic tests in "E2E Borrow Graph". Part 2 — &mut e parser surface LANDED (Refs #177, gate 278→281, zero Menhir conflict delta — 21 S/R + 1 R/R baseline held; AMP MUT e is unambiguous): the exclusive-borrow expression is now expressible, so the pt1 shared-XOR-exclusive rules (ConflictingBorrow/UseWhileExclusivelyBorrowed) are reachable from source for the first time (3 hermetic "E2E Borrow Graph" tests; &mut e typed/codegen’d like &e — exclusivity is a static borrow property). &-in-{ literals and bare block-statements already parse on main; → &T/&T type sigil deliberately not added — ref T/mut T keyword types already express reference types; a &T sigil is duplicate surface (ADR territory, not a soundness gap). Part 3 Slice A — NLL last-use expiry LANDED (Refs #177): a forward pre-pass (compute_last_use_index) maps each symbol to the greatest statement index that mentions it; after each statement, check_block expires any ref-binding introduced in that block whose binder is now dead, releasing the underlying borrow. Unblocks the canonical NLL patterns (let r = &x; print(r); x = 2; let m = &mut x; let y = *m; x) while preserving soundness. *Part 3 Slice B LANDED (Refs #177): flow-sensitive escape via re-assignment — outer = &y in StmtAssign now pre-releases the held borrow and re-binds the (binder → new_borrow) ref-graph entry to the freshly-created borrow, so the NLL last-use + return-escape analyses see the current referent after re-assignment, not the stale original. Pre-release order chosen so the same-target reborrow (r = &mut x while r already holds &mut x) does not trip ConflictingBorrow on the about-to-be-replaced exclusive borrow. 3 hermetic tests in "E2E Borrow Graph" (old released, new tracked by NLL, anti-regression that new borrow still protects its new target). Part 3 Slice C-light LANDED (Refs #177): CFG-join semantics for non-match join constructs — ExprHandle handler arms and ExprTry catch arms are now isolated via snapshot-restore-merge, extracted into a merge_arm_results helper that mirrors ExprMatch’s inlined logic (intersection on borrows, union on moves, first-error propagation). Moves/borrows from arm i no longer pollute arm i+1; `finally runs deterministically against the merged post-catch state. 2 hermetic tests in "E2E Borrow Graph" (positive: two catch arms can independently move the same value; anti-regression: body-side moves still propagate past the try, preserving conservative correctness). Residual (Slices C-full / C' / D): true Polonius origin/region variables on TyRef/TyMut with subset constraints and a datalog- style loan-live-at-point solver (architectural change to the type system; ADR-gated); loop soundness via a 2-iteration check on StmtWhile/StmtFor (coupled to a StmtAssign clear-on-rewrite fix — assignment is currently treated as a read of LHS, so the naive 2-iter spuriously fails on legitimate re-assignment loops); reborrow through indirection (r = some_other_ref_var RHS, parks with the let-graph’s same restriction); tighter quantity-checker integration for captured linears.

S1

pt1 #240 + pt2 return-escape + &mut surface + pt3 Slices A+B+C-light DONE (Refs #177); residual = Slices C-full (origin variables, ADR-gated), C' (loop soundness), D (quantity integration), plus ref-to-ref binding — issue #177

CORE-02

Effect-handler dispatch on WasmGC (was UnsupportedFeature; the chosen path is CPS over the EH proposal). The #225 CPS line closed the async slice; #234 generalised the boundary recogniser from a hardcoded name set to "any call whose effect row ⊇ `Async`".

S2

CLOSED 2026-05-19 — #225 line CLOSED PR1..PR3d+PR4; #234 ADR-016 delivered end-to-end (S1 #270 ADR; S2a #275 shared call-site numbering lib/effect_sites.ml; S2b #276 typecheck builds the ordinal→effect side-table; S3 #277 pipeline threads it + codegen boundary predicate switched + user-defined-Async e2e tests/codegen/effect_async_boundary.affine; S4 #278 hardcoded async_primitives set retired — boundary is now exactly Effect_sites.is_async_call). Issue #234 closed completed. Table-miss fallback (Effect_sites.is_async_call = false ⇒ no transform) remains as the sound table-empty / count-mismatch path.

CORE-03

ADR-014: module-qualified type/effect path. Decision settled (both ./:: accepted, Pkg::Type canonical, .:: for free via the ::-fold). Was the estate’s dominant parse blocker (525/1177 .affine). Grammar LANDED + MERGED (PR #241, Refs #228, zero Menhir conflict delta — 21 S/R + 1 R/R unchanged); ADR-014 recorded in META.a2ml + SETTLED-DECISIONS.adoc. Supersedes DRAFT #231.

S1

grammar merged (#241). Post-#228 estate re-audit DONE — true #229 scope is ~84 files/12 repos (not the 491 DRIFT; bulk is non-RS, out of contract); authoritative ledger + language-grounded canonical map + ESC-01..03 escalations: RESCRIPT-ELIMINATION.adoc

CORE-04

Traits: associated-type substitution, where-clause supertraits, coherence checking.

S2

partial

CORE-05

Dependent/refinement types: predicate reduction / SMT.

S3

parse-only

Section C — STDLIB

ID

Item

Sev

Status

STDLIB-AOT

All stdlib files compile resolve→typecheck→codegen, CI-gated

S1

CLOSED 2026-05-18 (#128/#135; test/test_stdlib_aot.ml)

STDLIB-01

Portable Http.fetch primitive

S2

DONE — #160 + #225 joint-closed. Deno-ESM (#226) + typed-wasm CPS line PR1..PR3d (#227/#233/#236/#237/#238/#266) all merged; ADR-013 delivery plan complete; convergence ABI shared w/ Ephapax

STDLIB-02

Portable Json primitive

S2

LANDED (Refs #161 #246): stdlib/json.affine — pure recursive Json ADT + encoders/decoders/ get_field/stringify, AOT-gated (#136, gate 278→279). Target-agnostic (no host dep); String→Json parse is the Http typed-boundary bridge (ADR-018), not a hand-rolled parser. Closes ESC-02 #246 (the #229 JSON.t target)

STDLIB-03

Dict/Map keyed container

S2

LANDED (Refs #162 #247): stdlib/dict.affine — keyed container over [(String, V)] (the json::JObject representation): empty/from_pairs/get/contains/size/ insert/set/remove/keys/values; AOT-gated (#136). Closes ESC-03 #247 (the #229 Dict.t target); unblocks the additive Http.affine headers→Dict upgrade

STDLIB-04

Residual extern builtins → real implementations (umbrella; split into 04a–04e 2026-05-24 per per-extern audit in STDLIB-EXTERN-AUDIT.adoc, one row per PR)

S3

open (5 sub-rows)

STDLIB-04a

Mut effect externs (make_ref/get/set) — LANDED (Refs #328): interp uses VMut cell (lib/interp.ml); Deno codegen lowers to {cell: x} single-field object (lib/codegen_deno.ml); 3 hermetic e2e tests in "E2E STDLIB-04a Mut #328" (Int + String round-trips + Deno codegen cell-shape assertion)

S3

DONE 2026-05-24 (Refs #328)

STDLIB-04b

Throws extern error<T> — missing in all backends (lib/interp.ml, lib/js_codegen.ml, lib/codegen_deno.ml); sibling panic is wired and error should mirror it (divergent T)

S3

open — issue #329

STDLIB-04c

string_concat extern — REMOVED (Refs #330): the canonical surface is the ++ operator (lowered in Value.binop_string and __as_concat); the extern was declared but never wired in any backend nor called from any stdlib/test/fixture — dead surface. The contract is now operator-only and one-source-of-truth.

S3

DONE 2026-05-24 (Refs #330)

STDLIB-04b

Throws extern error<T>LANDED (Refs #329): mirrors panic’s divergent semantics with a polymorphic return (<T>` unifies with the call-site expectation, unobservable at runtime). Wired in interp (RuntimeError), Deno codegen (throw new Error), resolve seed, and typecheck as a scheme (poly1 so each call instantiates a fresh tyvar). 3 hermetic tests in "E2E STDLIB-04b error #329".

S3

DONE 2026-05-24 (Refs #329)

STDLIB-04c

string_concat extern — no direct wiring found; ` operator independently lowered. Decide: remove (operator-only) or wire to mirror `

S3

open — issue #330

STDLIB-04d

IO externs (print/println/read_line/read_file/ write_file) — DONE (Refs #331): 5 hermetic tests in "E2E STDLIB-04d IO #331" — write_fileread_file round-trip on a real tmpfile, read_file on a missing path returns Err (not raise), print/println exec without error, Deno codegen wires both into the prelude. read_line is interactive and intentionally out of scope (the TEA-bridge tests already exercise the redirected-stdin path). No impl change; was test-debt, not impl-debt.

S3

DONE 2026-05-24 (Refs #331)

STDLIB-04e

Pure externs (int_to_string/string_to_int/ string_length) — DONE (Refs #332): int_to_string
string_length were already real-wired; string_to_int was unwired dead surface (re-audit caught the gap the initial sweep missed — same trap STDLIB-04c removed). Now the typed-alias of parse_int in interp + Deno codegen + resolve/typecheck seeds. 4 hermetic tests in "E2E STDLIB-04e Pure #332" lock the round-trip semantics.

S3

DONE 2026-05-24 (Refs #332)

Section D — INT (ecosystem integration)

Full table with blocked-by in ECOSYSTEM.adoc §INT-01..12. Substrate summary:

ID

Item

Sev

Status

INT-01

Cross-module WASM import emission (substrate). use Mod::{fn} / use Mod::* → real (import "Mod" "fn" …), callee exports the symbol, indices line up: PROVEN end-to-end (two separately-compiled .wasm link + execute, cross-call = 42) and regression-locked — hermetic structural test in the gate (271/271) + reproducible deno harness tests/modules/xmod-link/. Multi-file libraries via use Mod::{…} are shippable. Qualified-value path now wired: use Mod; (or use Mod as M;) + Mod.fn(x) resolves+typechecks — pure parse-boundary lowering Resolve.lower_qualified_value_paths (applied in parse_with_face; embedders bypassing it call it directly — the formatter is unaffected, so source Mod.fn is preserved on fmt); regression-locked (4 hermetic tests, "E2E Qualified Value #178"). Remaining (distinct, NOT this unit — a parser gap, not the resolver): Mod::fn(x) in expression position is a parse error (::-in-value-expr unwired; :: reserved for Type::Variant).

S1

use ::{}/::* + use Mod;/as-qualified Mod.fn(x) DONE (PR Refs #178); ::-in-expression a separate parser follow-up

INT-02

Host-agnostic loader bridge

S1

PROVEN + locked (Refs #179): packages/affine-js loader (SAT-02 fixed; Deno/Node/browser parity, multi-ns import object, ownership accessor); 14 unit tests via pinned deno task test + tests/modules/loader-bridge/ e2e on real compiler-emitted xmod wasm (closes INT-01↔INT-02). Unblocks INT-05/08/11

INT-03

WASI preview2 / host I/O

S1→S6a

#180 ADR-015 (full Component-Model re-target, S1..S6); S2 toolchain #251 closed; S3 componentize done; S4a (clock) + S4b (env_count, arg_count) DONE — on-demand preview1 imports via Effect_sites pre-scan, canonical-order indexing through ctx.wasi_func_indices; combo regression proves no collision. String accessors (env_at/arg_at) gated on byte-level wasm IR (I32Load8U/I32Store8 absent today) — tracked next slice. S6a (WIT export lifting) DONE: lib/codegen.ml auto-emits a _start : () → () shim whenever a parameter-less fn main() is present (additive, no regression on reactor consumers); tools/componentize.sh --command wraps with the fetch-pinned command adapter (sha256 8ff2ea78… / wasmtime v44.0.1, provisioned alongside the reactor adapter); tests/componentize/command_smoke.sh gates the contract end-to-end — wasi:cli/run lifted, ownership section survives, wasmtime run exits 0. Real-host main-invoke now works via wasmtime run <component>. Remaining S6 sub-slices: S5 (native clocks/env/argv), S6b (wasi:sockets), S6c (flip the default wasm target from preview1 → component) regression proves no collision. S5 (env_at/arg_at) DONE — wasm IR extended with the byte-level load/store family (I32Load8U/I32Store8 and siblings); accessors lower to on-demand environ_get/args_get imports paired with the existing *_sizes_get (dedup keeps each WASI import exactly once even when both *_count and *_at are used in the same unit); guest allocates a length-prefixed AS string and byte-copies from the WASI buffer. Real-host main-invoke = S6 (WIT export lifting)

INT-04

Publish to JSR/npm

S2

#181 packaging READY (dry-run green, manual workflow); compiler-binary distribution decided = ADR-019 (#260, Releases + thin Deno/JSR shim, staged S1..S4; per-file record decisions/0019-compiler-distribution.adoc) — S1/S2/S3 merged (#283/#284/#285); S4 done — INT-10 closed (#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 fast-check). @hyperpolymath/affine-js + @hyperpolymath/affinescript-tea remain dry-run-OK / not-yet-dispatched. Compiler version-string drift fixed via #297/#300 (single source of truth lib/version.ml + release.yml tag-time bake step — v0.1.1 binary now self-reports 0.1.1). Repo-wide SPDX surface relicensed MPL-2.0 → MPL-2.0 (#301/#304; PMPL preserved as the narrative-preferred licence in root LICENSE).

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 fixed; runtime blocked by #255 (wasm loop-codegen defect)

INT-10

affinescript-lsp distribution

S2

DONE end-to-end live (#282, ADR-019 S4): LSP resolves the compiler via AFFINESCRIPT_COMPILERaffinescript on PATH → the @hyperpolymath/affinescript shim (src/compiler.rs); no bespoke bundling; locate/exec smoke + resolution unit tests green. As of 2026-05-20 the shim is published on JSR (@hyperpolymath/affinescript@0.1.2) and pins all three v0.1.1 binaries by SHA256, so the shim resolution path actually executes end-to-end now (was code-correct but inert before today’s publish).

INT-05/06/09/11/12

ledger-only; filed when blocker closes

planned

Section E — SAT (satellite repos)

ID

Item

Sev

Status

SAT-01

affinescript-dom reconciler (skeleton → real)

S2

open (=INT-08)

SAT-02

packages/affine-js hardcoded path / env-only imports

S1

FIXED by INT-02 (Refs #179): Deno.readFile(url.pathname) replaced by host-agnostic readBytes; env-only import shape replaced by multi-namespace buildImportObject; mod.js consumes the loader. Proven + locked (see INT-02)

SAT-03

affinescript-tea runtime build-out

S2

open (=INT-07)

SAT-04

affinescript-cadre router runtime

S2

planned (=INT-09)

SAT-05

affinescript-pixijs migration prerequisite

S3

open #56

Stage E — typed-wasm convergence runway

Formal interface spec: specs/TYPED-WASM-INTERFACE.adoc (+ machine companion). Widening roadmap (tranches A..E, recommended sequencing): specs/TYPED-WASM-ROADMAP.adoc. Proposed ADRs: ADR-020 (schema versioning), ADR-021 (multi-producer coordination model) — both PROPOSED in .machine_readable/6a2/META.a2ml.

ID

Item

Sev

Status

CONV-01

Estate-wide re-validation of the #199/#205 closure ABI (static → real wasm engine)

S2

open #235

CONV-02

Effect-threaded async-boundary detection (generalise the structural-conservative recogniser)

S2

CLOSED 2026-05-19 — #234 DELIVERED end-to-end (ADR-016 S1..S4; PRs #270/#275/#276/#277/#278). See CORE-02 above for the resolution narrative.

CONV-03

#225/#160 convergence ABI matured to "shared with Ephapax"

S1

partial (PR3a/b/c merged)

CONV-04

Widen emitted-wasm enforcement beyond L7+L10 toward L1–6/L13–16

S2

L13 (module isolation, negative form) DONE — Tw_verify.verify_module_isolation (carrier-free, no ABI change). L1–6/L14–16 need a new carrier section = multi-producer ABI proposal (filed for typed-wasm; NOT unilateral). Rust-verifier mirror + C5.1 = cross-repo follow-ups. Per-tranche detail in TYPED-WASM-ROADMAP (Tranches B/C/D)

CONV-05

INT-12: AffineScript-emitted fixtures into typed-wasm crates/typed-wasm-verify/tests/cross_compat.rs (typed-wasm "C5.1")

S1

planned — coordinate Refs hyperpolymath/typed-wasm

Update protocol

  • One PR per ledger unit; Refs #N (never Closes on the #175 epic — only the owner closes it).

  • Every capability-affecting PR updates CAPABILITY-MATRIX.adoc and this ledger in the same change; STATE.a2ml mirrors after.

  • dune runtest --force must stay green (baseline 260, 2026-05-19).

  • typed-wasm ABI changes are multi-producer: coordinate with hyperpolymath/typed-wasm and hyperpolymath/ephapax.