Skip to content

Commit ff7ccd7

Browse files
feat(wasi): land #485 filesystem, #487 sockio, #486 wrap-default, #56-A (#757)
Preview1 lowerings and wrap-default machinery for the leftover WASI/DOM slices that blocked closing GitHub index #175. ## #485 S5 `wasi:filesystem` - Guest builtins `file_open` / `file_read` / `file_fd_write` / `file_close` lower to preview1 `path_open` / `fd_read` / `fd_write` / `fd_close` - Effect `File` reserved; dirfd 3 is the first `--dir` preopen - Stub tests under `tests/codegen/` plus gated `tests/componentize/filesystem_smoke.sh` (`wasmtime run --dir host::.`) ## #487 sock recv/send/accept - `net_recv` / `net_send` / `net_accept` → `sock_recv` / `sock_send` / `sock_accept`, Effect `Net` - Stub tests plus gated `tests/componentize/sockio_smoke.sh` ## #486 wrap default, not the one-way door - `tools/componentize.sh` now defaults to `--command` - S3 reactor smoke requests `--reactor` explicitly - Compiler still emits preview1 core wasm; native-preview2 import cleanup remains the one-way door ## #56-A + Pixi gap-fill - `stdlib/Dom.affine`, `stdlib/Console.affine` - `affinescript-dom` convenience constructors (`div`/`h1`/`p`/… + `replaceBody`) - Pixi Point/Rectangle/Circle, tint/blend, hitArea/mask, BlurFilter, NineSlice, Assets, event coords - PixiUI ProgressBar/List/Input; PixiSound `isPlaying`/`duration` Ledgers updated: `docs/TECH-DEBT.adoc`, `docs/ECOSYSTEM.adoc`, `docs/CAPABILITY-MATRIX.adoc`. Refs #485 #486 #487 #56 --------- Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com> Co-authored-by: Jonathan D.A. Jewell <hyperpolymath@users.noreply.github.com>
1 parent c91a9df commit ff7ccd7

39 files changed

Lines changed: 1524 additions & 66 deletions

‎affinescript-dom/src/dom.affine‎

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,45 @@ pub fn text(content: String) -> VNode = VText(content);
6060
pub fn h(tag: String, attrs: [(String, String)], children: [VNode]) -> VNode =
6161
VElem(tag, attrs, children);
6262

63+
/// Convenience constructors (#56-A). Thin wrappers over `h` so idaptik's
64+
/// pilot `Dom.div` / `Dom.h1` / `Dom.p` surface compiles without going
65+
/// through the low-level tag string.
66+
pub fn div(attrs: [(String, String)], children: [VNode]) -> VNode =
67+
h("div", attrs, children);
68+
69+
pub fn h1(attrs: [(String, String)], content: String) -> VNode =
70+
h("h1", attrs, [text(content)]);
71+
72+
pub fn h2(attrs: [(String, String)], content: String) -> VNode =
73+
h("h2", attrs, [text(content)]);
74+
75+
pub fn h3(attrs: [(String, String)], content: String) -> VNode =
76+
h("h3", attrs, [text(content)]);
77+
78+
pub fn p(attrs: [(String, String)], content: String) -> VNode =
79+
h("p", attrs, [text(content)]);
80+
81+
pub fn span(attrs: [(String, String)], content: String) -> VNode =
82+
h("span", attrs, [text(content)]);
83+
84+
pub fn button(attrs: [(String, String)], content: String) -> VNode =
85+
h("button", attrs, [text(content)]);
86+
87+
pub fn input(attrs: [(String, String)]) -> VNode =
88+
h("input", attrs, []);
89+
90+
pub fn a(attrs: [(String, String)], content: String) -> VNode =
91+
h("a", attrs, [text(content)]);
92+
93+
pub fn img(attrs: [(String, String)]) -> VNode =
94+
h("img", attrs, []);
95+
96+
pub fn ul(attrs: [(String, String)], children: [VNode]) -> VNode =
97+
h("ul", attrs, children);
98+
99+
pub fn li(attrs: [(String, String)], children: [VNode]) -> VNode =
100+
h("li", attrs, children);
101+
63102
// `len` is not available in the standalone wasm-AOT subset; a `for`-count
64103
// helper is (proven: tests/codegen/test_for_loop). Monomorphic, not
65104
// generic, since wasm codegen generic support is not relied on here.
@@ -103,6 +142,12 @@ pub fn mount(selector: String, vnode: VNode) -> Bool {
103142
}
104143
}
105144

145+
/// Replace `document.body` contents with `vnode` (#56-A). Equivalent
146+
/// to `mount("body", vnode)`. Declared below `mount` because codegen
147+
/// is single-pass in source order.
148+
pub fn replaceBody(vnode: VNode) -> Bool =
149+
mount("body", vnode);
150+
106151
// ── Reconciler: minimal mutation between two VNode trees ─────────────────────
107152

108153
fn attr_has(attrs: [(String, String)], key: String) -> Bool {

‎docs/CAPABILITY-MATRIX.adoc‎

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,11 @@ The compiler emits to many targets. *Maturity is not uniform; do not claim
176176
|Target |Status |Notes
177177

178178
|WASM (core) |works |Cross-module imports + `extern fn` → WASM import
179-
emission. The reference target.
179+
emission. The reference target. WASI preview1 on-demand imports cover
180+
clock/env/args/sockets/filesystem (`file_open`/`file_read`/
181+
`file_fd_write`/`file_close`, `net_recv`/`net_send`/`net_accept`);
182+
`tools/componentize.sh` defaults to the command adapter (#486). Native
183+
preview2 import lowering is still the one-way door.
180184

181185
|WASM-GC |partial |Variant-with-args + same-arity `PatCon` destructuring;
182186
silent-bad-codegen fallbacks eliminated. Mixed-arity matches need uniform
@@ -285,9 +289,14 @@ their own ledger (link:SOUNDNESS.adoc[SOUNDNESS.adoc]), gated by
285289
* typed-wasm is *not* an AffineScript subsystem. It is a separate,
286290
language-agnostic target with its own repo, proofs, and other producers
287291
(ephapax). AffineScript is one producer among several.
288-
* The satellite ecosystem is mostly scaffold/skeleton — see the satellite
289-
registry in `ECOSYSTEM.adoc`. `affinescript-tea`/`-dom-loader`/`-cadre`
290-
were imaginary until the #175 scaffolds; `-dom`/`-pixijs` are skeletons.
292+
* The satellite ecosystem is mixed maturity — see the satellite registry
293+
in `ECOSYSTEM.adoc`. `affinescript-tea` (INT-07/#182) and
294+
`affinescript-dom` (INT-08/#183) shipped runtimes; `affinescript-cadre`
295+
(INT-09) closed 2026-07-25. `affinescript-pixijs` in-tree bindings
296+
(`stdlib/Pixi.affine` + UI/Sound) plus 56-A `stdlib/Dom.affine` /
297+
`stdlib/Console.affine` landed 2026-09-21; full idaptik surface is
298+
still open (#56). The `-dom-loader` satellite was folded into
299+
`affine-js` (#489).
291300

292301
== Change control
293302

‎docs/ECOSYSTEM.adoc‎

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,20 @@ files; `test/test_stdlib_aot.ml`; issues #128/#135.
7575
|*D* |Base-language soundness + ecosystem connective tissue: CORE-01 borrow
7676
Phase-3 (#177); the INT-01..12 integration roadmap; the satellite registry
7777
made real; #228/ADR-014 module-qualified paths (estate port unblocker). |
78-
*ACTIVE — current frontier* |This stage. Substrate = INT-01..04 + CORE-01.
78+
*CLOSED 2026-07-25* |Substrate (INT-01..04 + CORE-01) closed 2026-05-31;
79+
remaining original #175 children INT-07 (#182) and INT-08 (#183) closed
80+
2026-07-25. Residual WASI follow-ups #485 (S5 filesystem) and #487
81+
(socket recv/send/accept) have preview1 lowerings + gated smokes in
82+
tree; #486 flipped the wrap default to `--command` without the one-way
83+
compiler re-target. Satellite remainder is #56 (56-A Dom/Console + Pixi
84+
gap-fill landed). Stage E is now the frontier.
7985

8086
|*E* |typed-wasm convergence hardening (the transition runway): the
8187
AffineScript↔typed-wasm contract widened from L7+L10 toward full
8288
L1–6/L13–16 emitted-wasm enforcement; estate-wide re-validation (#235);
8389
effect-threaded async-boundary recogniser (#234); the #225/#160 convergence
84-
ABI matured to "shared with Ephapax". |*planned* |Begins when D's substrate
85-
(INT-01..04, CORE-01) is closed; ends at a stable, multi-producer
90+
ABI matured to "shared with Ephapax". |*ACTIVE — current frontier* |D's
91+
substrate (INT-01..04, CORE-01) is closed. Ends at a stable, multi-producer
8692
typed-wasm convergence ABI.
8793
|===
8894

@@ -154,7 +160,10 @@ runtime is *VERIFIED end-to-end* (2026-07-07): `affinescript-dom/e2e/run.sh`
154160
drives mount + in-place attr patch + text update + surplus-child removal
155161
against a real Int-handle host DOM, mutation log asserted.
156162

157-
|`affinescript-pixijs` |skeleton |Migration-prerequisite scaffold (#56).
163+
|`affinescript-pixijs` |in-tree bindings |#56 partial: `stdlib/Pixi.affine`
164+
(+ UI/Sound) is the operational binding; 56-A also landed
165+
`stdlib/Dom.affine` + `stdlib/Console.affine`. Remaining: full idaptik
166+
surface.
158167

159168
|`affinescript-vite` |scaffold |Build-tool integration shell.
160169

@@ -188,8 +197,10 @@ object, `typedwasm.ownership` accessor.
188197
== Integration roadmap — INT-01..12
189198

190199
Critical path: *INT-01..INT-04 are substrate and block most satellites.*
191-
Filed sub-issues are children of #175; severity/blocked-by also in
192-
link:TECH-DEBT.adoc[TECH-DEBT.adoc].
200+
GitHub index #175: 8/8 original sub-issues complete; severity/blocked-by
201+
also in link:TECH-DEBT.adoc[TECH-DEBT.adoc]. Residual WASI work is
202+
#485/#486/#487 (preview1 FS + sockio + wrap-default in tree; native
203+
preview2 re-target still the one-way door); satellite remainder is #56.
193204

194205
[cols="1,3,1,2"]
195206
|===
@@ -239,16 +250,15 @@ dropped; 81d9fc7). Test gates:
239250
`tests/componentize/{smoke,command_smoke,sockets_smoke}.sh` cover
240251
the contract end-to-end; ownership section byte-survives every
241252
wrap; combo-import canonical-order regression. Residual (filed
242-
2026-05-31): #485 — S5 native `wasi:filesystem`
243-
(open/read/write/close), unblocks INT-06 (server-side runtime
244-
profile); #486 — S6c flip default wasm target preview1 →
245-
component, bundled with native-preview2 cleanup replacing the
246-
on-demand preview1 shims emitted by S4a/S4b/S6b with direct
247-
`wasi:clocks` / `wasi:cli` / `wasi:sockets` calls (only pays off
248-
once preview2 is the default — the one-way door that ends
249-
reversibility); #487 — socket recv/send/accept primitives
250-
(byte-level buffer / network-address marshalling, helper mirrors
251-
`gen_str_at_via_get`). WIT world of record: `wit/affinescript.wit`
253+
2026-05-31, status 2026-09-21): #485 — S5 native `wasi:filesystem`
254+
preview1 lowering LANDED (`file_open`/`file_read`/`file_fd_write`/
255+
`file_close`, Effect `File`, gated
256+
`tests/componentize/filesystem_smoke.sh`); #486 — S6c wrap default
257+
flipped to `--command` (S3 reactor smoke now passes `--reactor`);
258+
compiler still emits preview1 core; native-preview2 cleanup remains
259+
the one-way door; #487 — `net_recv`/`net_send`/`net_accept` preview1
260+
lowering LANDED (gated `tests/componentize/sockio_smoke.sh`). WIT
261+
world of record: `wit/affinescript.wit`
252262
|INT-04 |Publish compiler + runtime to JSR (then npm) |#181 |runtime
253263
packaging READY (affine-js + affinescript-tea JSR dry-run green;
254264
manual-only `publish-jsr.yml`; docs/PACKAGING.adoc). INT-01 dep
@@ -258,11 +268,11 @@ auth). Compiler-binary distribution = design fork #260
258268
(INT-02 dep cleared 2026-05-31 via #179; no other blockers — next-up
259269
candidate for an issue-spinout)
260270
|INT-06 |Server-side runtime profile (on INT-03 WASI p2) |ledger-only
261-
|planned (blocked by #485)
262-
|INT-07 |`affinescript-tea` runtime satellite |#182 |runtime + run loop
271+
|planned (#485 FS slice unblocked 2026-09-21)
272+
|INT-07 |`affinescript-tea` runtime satellite |#182 **CLOSED 2026-07-25** |runtime + run loop
263273
shipped (`TeaApp`/`parseTeaLayout`, Linear-msg enforced); INT-01 dep
264274
cleared (#253). Router/nav = separate INT-09
265-
|INT-08 |DOM reconciler in `affinescript-dom` |#183 |reconciler
275+
|INT-08 |DOM reconciler in `affinescript-dom` |#183 **CLOSED 2026-07-25** |reconciler
266276
implemented + compiles (resolve→typecheck→codegen→wasm); `.as`→`.affine`
267277
corrected. INT-02 dep cleared. #255 (wasm loop-codegen defect) that gated
268278
the runtime is FIXED (PR #257, closed 2026-05-19); runtime VERIFIED

‎docs/TECH-DEBT.adoc‎

Lines changed: 57 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,17 @@ Reconstructed and made authoritative 2026-05-19 (it was cited by #175–183 /
1717
#228 / #177 but never committed). For the spine + contract see
1818
link:ECOSYSTEM.adoc[ECOSYSTEM.adoc]; for readiness see
1919
link:CAPABILITY-MATRIX.adoc[CAPABILITY-MATRIX.adoc].
20+
21+
GitHub index #175: **8/8 original sub-issues CLOSED** as of 2026-07-25
22+
(#176 DOC, #177 CORE-01, #178 INT-01, #179 INT-02, #180 INT-03,
23+
#181 INT-04-JSR, #182 INT-07, #183 INT-08). The GitHub ticket is a pure
24+
index whose children are complete; this ledger remains the durable
25+
index. Residual WASI follow-ups #485 (S5 filesystem) and #487
26+
(socket recv/send/accept) have preview1 lowerings + gated smokes in
27+
tree; #486 flipped the *wrap* default to `--command` without the
28+
one-way compiler re-target (native-preview2 cleanup still open).
29+
Satellite remainder is #56 (56-A Dom/Console + Pixi gap-fill landed;
30+
full idaptik surface still open).
2031
====
2132

2233
toc::[]
@@ -36,8 +47,8 @@ Stage D CLOSED ── CORE-01 (#177) ─┐ (base l
3647
└─ INT-04 (#181) ◄─┘ (◄ INT-01) │
3748
ADR-014 (#228) ── estate port unblocker, S1 │
3849
▼
39-
Stage E planned ── typed-wasm convergence hardening
40-
(#234, #235, #225/#160 line, INT-12) ──► stable multi-producer ABI
50+
Stage E ACTIVE ── typed-wasm convergence hardening
51+
(#234 closed, #235, #225/#160 line, INT-12) ──► stable multi-producer ABI
4152
----
4253

4354
The mandate's order of operations: *CORE-01 first* (the one named
@@ -401,11 +412,21 @@ export lifting via `_start : () -> ()` shim around parameter-less
401412
`wasi_snapshot_preview1.sock_shutdown` (command adapter bridges to
402413
`wasi:sockets/tcp`; 81d9fc7). Gates:
403414
`tests/componentize/{smoke,command_smoke,sockets_smoke}.sh`.
404-
Residual (filed 2026-05-31): #485 S5 native `wasi:filesystem`
405-
(open/read/write/close — unblocks INT-06), #486 S6c flip default
406-
wasm target preview1 → component + native-preview2 cleanup (one-way
407-
door), #487 socket recv/send/accept primitives (byte-level buffer
408-
/ network-address marshalling)
415+
Residual (filed 2026-05-31, status 2026-09-21):
416+
#485 S5 native `wasi:filesystem` — *preview1 lowering LANDED*
417+
(`file_open`/`file_read`/`file_fd_write`/`file_close` →
418+
`path_open`/`fd_read`/`fd_write`/`fd_close`, Effect `File`,
419+
dirfd 3, combo canonical-order lock + gated
420+
`tests/componentize/filesystem_smoke.sh` hermetic `--dir`
421+
round-trip). Unblocks INT-06's FS slice.
422+
#486 S6c — *wrap default LANDED* (`tools/componentize.sh` now
423+
defaults to `--command`; S3 reactor smoke requests `--reactor`
424+
explicitly). Compiler still emits preview1 core wasm;
425+
native-preview2 import cleanup remains the one-way door.
426+
#487 socket recv/send/accept — *preview1 lowering LANDED*
427+
(`net_recv`/`net_send`/`net_accept` → `sock_recv`/`sock_send`/
428+
`sock_accept`, Effect `Net`, gated
429+
`tests/componentize/sockio_smoke.sh`)
409430
|INT-04 |Publish to JSR/npm |S2 |#181 packaging READY (dry-run green,
410431
manual workflow); compiler-binary distribution decided = **ADR-019**
411432
(#260, Releases + thin Deno/JSR shim, staged S1..S4; per-file record
@@ -420,12 +441,15 @@ drift fixed via #297/#300 (single source of truth `lib/version.ml`
420441
`0.1.1`). Repo-wide SPDX surface relicensed MPL-2.0 →
421442
MPL-2.0 (#301/#304; PMPL preserved as the narrative-preferred
422443
licence in root `LICENSE`).
423-
|INT-07 |`affinescript-tea` runtime |S2 |#182 runtime + run loop shipped
424-
(TeaApp/parseTeaLayout, Linear-msg enforced); INT-01 cleared (#253)
425-
|INT-08 |DOM reconciler |S2 |#183 implemented + compiles; `.as`→`.affine`
426-
fixed; #255 (wasm loop-codegen defect) that gated the runtime is fixed
427-
(PR #257, closed 2026-05-19) — runtime VERIFIED end-to-end 2026-07-07 via
428-
`affinescript-dom/e2e/run.sh`
444+
|INT-07 |`affinescript-tea` runtime |S2 |**#182 CLOSED 2026-07-25** —
445+
runtime + run loop shipped (TeaApp/parseTeaLayout, Linear-msg enforced);
446+
INT-01 cleared (#253)
447+
|INT-08 |DOM reconciler |S2 |**#183 CLOSED 2026-07-25** — implemented +
448+
compiles; `.as`→`.affine` fixed; #255 (wasm loop-codegen defect) that
449+
gated the runtime is fixed (PR #257, closed 2026-05-19) — runtime
450+
VERIFIED end-to-end 2026-07-07 via `affinescript-dom/e2e/run.sh`
451+
|INT-09 |`affinescript-cadre` router/navigation runtime |S2 |**CLOSED
452+
2026-07-25** (CadreRouter JS wrapper + E2E tests)
429453
|INT-10 |`affinescript-lsp` distribution |S2 |**DONE end-to-end live**
430454
(#282, ADR-019 S4): LSP resolves the compiler via `AFFINESCRIPT_COMPILER`
431455
→ `affinescript` on `PATH` → the `@hyperpolymath/affinescript` shim
@@ -434,22 +458,34 @@ unit tests green. As of 2026-05-20 the shim is published on JSR
434458
(`@hyperpolymath/affinescript@0.1.2`) and pins all three v0.1.1
435459
binaries by SHA256, so the shim resolution path actually executes
436460
end-to-end now (was code-correct but inert before today's publish).
437-
|INT-05/06/09/11/12 |ledger-only; filed when blocker closes |— |planned
461+
|INT-05 |Loader-driven multi-module app bundling |S2 |planned (INT-02 dep
462+
cleared 2026-05-31 via #179; candidate for an issue-spinout)
463+
|INT-06 |Server-side runtime profile (on INT-03 WASI p2) |S2 |planned
464+
(#485 FS slice unblocked 2026-09-21; remaining: native-preview2
465+
clocks/cli/sockets + a real server profile)
466+
|INT-11 |Browser host parity (`affine-js` loader + `affinescript-dom`
467+
reconciler end-to-end) |S2 |**CLOSED 2026-07-25**
468+
|INT-12 |typed-wasm convergence fixtures |S1 |planned (Stage E;
469+
coordinates with `hyperpolymath/typed-wasm` C5.1)
438470
|===
439471

440472
== Section E — SAT (satellite repos)
441473

442474
[cols="1,3,1,2"]
443475
|===
444476
|ID |Item |Sev |Status
445-
|SAT-01 |`affinescript-dom` reconciler (skeleton → real) |S2 |open (=INT-08)
477+
|SAT-01 |`affinescript-dom` reconciler (skeleton → real) |S2 |**DONE**
478+
(=INT-08, #183 CLOSED 2026-07-25) — runtime VERIFIED e2e 2026-07-07 via
479+
`affinescript-dom/e2e/run.sh`
446480
|SAT-02 |`packages/affine-js` hardcoded path / env-only imports |S1
447481
|*FIXED* by INT-02 (Refs #179): `Deno.readFile(url.pathname)` replaced by
448482
host-agnostic `readBytes`; `env`-only import shape replaced by
449483
multi-namespace `buildImportObject`; `mod.js` consumes the loader.
450484
Proven + locked (see INT-02)
451-
|SAT-03 |`affinescript-tea` runtime build-out |S2 |open (=INT-07)
452-
|SAT-04 |`affinescript-cadre` router runtime |S2 |planned (=INT-09)
485+
|SAT-03 |`affinescript-tea` runtime build-out |S2 |**DONE** (=INT-07,
486+
#182 CLOSED 2026-07-25)
487+
|SAT-04 |`affinescript-cadre` router runtime |S2 |**DONE** (=INT-09,
488+
CLOSED 2026-07-25)
453489
|SAT-05 |`affinescript-pixijs` migration prerequisite |S3 |open #56
454490
|===
455491

@@ -490,7 +526,10 @@ link:specs/TYPED-WASM-ROADMAP.adoc[TYPED-WASM-ROADMAP] (Tranches B/C/D)
490526
== Update protocol
491527

492528
* One PR per ledger unit; `Refs #N` (never `Closes` on the #175 epic — only
493-
the owner closes it).
529+
the owner closes it). Residual follow-ups after the original 8 children
530+
are #485/#486/#487/#56 — do not re-open #175 to track them. Owner may
531+
close #175 once those residuals are accepted; GitHub write is a PAT
532+
capability, not a ledger action.
494533
* Every capability-affecting PR updates `CAPABILITY-MATRIX.adoc` *and* this
495534
ledger in the same change; `STATE.a2ml` mirrors after.
496535
* `dune runtest --force` must stay green (baseline 260, 2026-05-19).

0 commit comments

Comments
 (0)