// SPDX-License-Identifier: CC-BY-SA-4.0
// SPDX-FileCopyrightText: 2024-2026 hyperpolymath
= AffineScript Coordination Ledger (TECH-DEBT)
:toc: macro
:toclevels: 3
:icons: font

[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
link:ECOSYSTEM.adoc[ECOSYSTEM.adoc]; for readiness see
link:CAPABILITY-MATRIX.adoc[CAPABILITY-MATRIX.adoc].
====

toc::[]

== Critical path (read first)

[source]
----
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  CLOSED ── 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
link:CAPABILITY-MATRIX.adoc[CAPABILITY-MATRIX.adoc]; this section keeps it
from re-drifting.

[cols="1,4,1"]
|===
|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/descriptiles/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 doc-truthing re-drift guard — `tools/check-doc-truthing.sh`
(toolchain-free bash), the single gate enforcing *both* halves of the
MONITOR. *Presence invariants (DOC-04/05):* 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. *Over-claim ratchet (DOC-08/09):*
a frozen-signature baseline (`tools/doc-overclaims.allow`) over README +
`docs/**` (excluding the two governance docs that quote the rule —
CAPABILITY-MATRIX + this ledger) fails any *new* backend-breadth /
"production-ready" / stdlib-% phrase beyond the 13-line accepted set
(future-tense roadmap milestones, dated history snapshots, the corrective
banners — none a live over-claim). Presence-checking handles the banners
(where "production-ready" legitimately appears); the frozen baseline adds
phrase detection without false positives. Re-baseline via `--update` /
`just doc-truth-bless`; the diff is the audit trail. 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*
|DOC-17 |Over-claim ratchet — *folded into DOC-16.* Briefly shipped as a
separate `tools/check-doc-overclaims.sh` (PR #475) alongside #476's banner
guard; consolidated into the single `tools/check-doc-truthing.sh` so the
two near-identically-named guards do not linger. The ratchet behaviour +
`tools/doc-overclaims.allow` baseline are unchanged — see DOC-16.
|*DONE 2026-05-30 (consolidated)*
|===

MONITOR enforcement (DOC-08/09): any PR re-introducing backend-breadth,
"production-ready", or stdlib-percentage over-claims must be rejected. As of
2026-05-30 this is enforced in-repo by the single unified guard
`tools/check-doc-truthing.sh` (DOC-16) — presence invariants *and* the
over-claim ratchet in one run. The external Hypatia/gitbot DOC rules remain
the estate-level backstop for anything outside both nets.

== Section B — CORE (compiler soundness / completeness)

[cols="1,3,1,2"]
|===
|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).
*Part 3 ref-to-ref binding LANDED* (PR #395, Refs #177): `let r2 = r`
and `r2 = r` (where `r` is a ref-binder) extend the borrow-graph by
aliasing `r2` to the same borrow `r` holds; `ref_source_borrow` unifies
`&p` / `&mut p` / ref-var cases so `record_ref_binding` and the
`StmtAssign` reborrow block both reach through one extra level of
indirection. Closes the reborrow-through-indirection gap.
*Part 3 Slice C' LANDED* (PR #396, Refs #177): loop soundness via a
2-iteration check on `StmtWhile`/`StmtFor`. Body runs once; state-fields
snapshot; cond+body run again from the post-iter-1 state. Body-moves
that aren't restored surface as `UseAfterMove` on the 2nd pass. Pairs
with `StmtAssign` clear-on-rewrite (PR #399 `is_whole_place_write`) so
legitimate re-init loops accept while loops with unrestored body-move
reject. *Part 3 Slice D LANDED* (PR #397, Refs #177): borrow-side
rejection of `@linear`-binding capture by a closure. Closures may be
called 0..N times, so capturing a `@linear`/`QOne` binding lifts its
consumption count out of the borrow checker's finite-once proof.
`state.linear_bindings` populated from `[@linear]` / `Cmd _` annotations
on params, `let`-statements, and `let`-expressions; `ExprLambda`
rejects free-vars whose sym-id is in that set with
`LinearCapturedByClosure` (errors at the lambda span, before the
downstream quantity-checker `QOmega`-scaled "used multiple times"
diagnostic). *Residual:* 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,
covered by ADR-022 (`docs/decisions/0022-polonius-origin-variables.adoc`,
PR #407) as a separate workstream; lexical checker is the merge oracle
through M3 per the ADR migration plan. Tighter quantity-checker
integration for captured linears is a small remaining nicety, not a
soundness gap. |S1 |*CLOSED 2026-05-30* (#177) — pt1 #240 + pt2
return-escape + `&mut` surface + pt3 Slices A+B+C-light+C'+D + ref-to-
ref binding DONE; residual Polonius work is ADR-022 (#407), a separate
workstream
|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: link:-ELIMINATION.adoc[-ELIMINATION.adoc]
|CORE-04 |Traits: associated-type substitution, where-clause supertraits,
generic-subsumption overlap. (Concrete-overlap coherence DONE — #559, see
link:SOUNDNESS.adoc[SOUNDNESS.adoc].) |S2 |partial
|CORE-05 |Dependent/refinement types: *removed in v1* (#558) — withdrawn, not
shipped unenforced. See link:SOUNDNESS.adoc[SOUNDNESS.adoc]. |S3
|removed
|===

== Section C — STDLIB

[cols="1,3,1,2"]
|===
|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
link:STDLIB-EXTERN-AUDIT.adoc[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_file` → `read_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)
|STDLIB-05 |db-theory triplet (`Sqlite` / `Transaction` / `Aggregate`)
— *LANDED* 2026-06-01..02. Sqlite.affine progressed across #522
(codegen foundation, 6 externs wired Deno-ESM end-to-end), #524
(prepared statements — `Stmt` opaque + 10 typed externs), and #525
(schema introspection + bulk I/O + error inspection — 6 externs).
Transaction.affine (#526) ships an affine-bounded `Tx` handle
(consumed exactly once by commit/rollback) + savepoint surface — 8
externs; companion proof
`docs/academic/proofs/db-theory-2-transaction-safety.md`.
Aggregate.affine (#527) ships SQL group-by + aggregation primitives —
7 externs; companion proof
`docs/academic/proofs/db-theory-3-aggregation-as-fold.md`. All three
modules picked up by the dynamic AOT gate; each ships its own
Deno-ESM smoke harness under `tests/codegen-deno/`. CHANGELOG sync
landed via #528. |S3 |DONE 2026-06-02 (PRs #522/#524/#525/#526/#527/#528)
|===

== Section D — INT (ecosystem integration)

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

[cols="1,3,1,2"]
|===
|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 |**#179 CLOSED 2026-05-31** —
*PROVEN + locked*: `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). INT-05/08/11
INT-02 dep cleared. Satellite-repo scope question = #489.
|INT-03 |WASI preview2 / host I/O |S1 |#180 ADR-015 (full
Component-Model re-target, S1..S6c). **#180 closed 2026-05-31 —
substrate done.** Shipped: S1 ADR (#252), S2 toolchain (#286,
closes #251), S3 componentize on-ramp via fetch-pinned
preview1→preview2 reactor adapter — `typedwasm.ownership` survives
the wrap (#288), S4a `clock_now_ms` (#289), S4b
`env_count`/`arg_count` (#290) — on-demand preview1 imports via
Effect_sites pre-scan, canonical-order indexing through
`ctx.wasi_func_indices`, combo regression proves no collision —
byte-level wasm IR + `env_at`/`arg_at` (#339, #364), S6a WIT
export lifting via `_start : () -> ()` shim around parameter-less
`fn main()` + `tools/componentize.sh --command` command adapter
(wasmtime v44.0.1, sha256 8ff2ea78…) — component exports
`wasi:cli/run@0.2.x`, real-host `wasmtime run <component>` exits 0
(#343), S6b sockets on-ramp via `net_shutdown` builtin lowering to
`wasi_snapshot_preview1.sock_shutdown` (command adapter bridges to
`wasi:sockets/tcp`; 81d9fc7). Gates:
`tests/componentize/{smoke,command_smoke,sockets_smoke}.sh`.
Residual (filed 2026-05-31): #485 S5 native `wasi:filesystem`
(open/read/write/close — unblocks INT-06), #486 S6c flip default
wasm target preview1 → component + native-preview2 cleanup (one-way
door), #487 socket recv/send/accept primitives (byte-level buffer
/ network-address marshalling)
|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
link:decisions/0019-compiler-distribution.adoc[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; #255 (wasm loop-codegen defect) that gated the runtime is fixed
(PR #257, closed 2026-05-19) — runtime VERIFIED end-to-end 2026-07-07 via
`affinescript-dom/e2e/run.sh`
|INT-10 |`affinescript-lsp` distribution |S2 |**DONE end-to-end live**
(#282, ADR-019 S4): LSP resolves the compiler via `AFFINESCRIPT_COMPILER`
→ `affinescript` 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)

[cols="1,3,1,2"]
|===
|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:
link:specs/TYPED-WASM-INTERFACE.adoc[specs/TYPED-WASM-INTERFACE.adoc]
(+ link:specs/TYPED-WASM-INTERFACE.a2ml[machine companion]).
Widening roadmap (tranches A..E, recommended sequencing):
link:specs/TYPED-WASM-ROADMAP.adoc[specs/TYPED-WASM-ROADMAP.adoc].
Proposed ADRs: ADR-020 (schema versioning), ADR-021 (multi-producer
coordination model) — both PROPOSED in
`.machine_readable/descriptiles/META.a2ml`.

[cols="1,3,1,2"]
|===
|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
link:specs/TYPED-WASM-ROADMAP.adoc[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`.
