diff --git a/docs/ECOSYSTEM.adoc b/docs/ECOSYSTEM.adoc index 634fe631..567d7aa6 100644 --- a/docs/ECOSYSTEM.adoc +++ b/docs/ECOSYSTEM.adoc @@ -188,9 +188,15 @@ link:TECH-DEBT.adoc[TECH-DEBT.adoc]. + `Mod.fn(x)` qualified-value path WIRED+locked (parse-boundary lowering; 4 hermetic tests). Distinct parser follow-up: `Mod::fn(x)` in expr position |INT-02 |Host-agnostic loader bridge (`affinescript-dom-loader`) |#179 |loader -landed in `packages/affine-js` (SAT-02 fixed; Deno/Node/browser parity, -multi-namespace import object, ownership-section accessor). S1; unblocks -INT-05/08/11. The `affinescript-dom-loader` satellite shell is downstream. +in `packages/affine-js` (SAT-02 fixed; Deno/Node/browser parity, +multi-namespace import object, ownership-section accessor). *PROVEN + +regression-locked:* 14 unit tests via pinned `deno task test` (was +flag-fragile — no run task) + `tests/modules/loader-bridge/` drives the +*real* loader API over genuine compiler-emitted cross-module wasm +(`readBytes`+`buildImportObject` link `CrossCallee.consume(42)`=42; +`parseOwnershipSection` reads a real Linear-param entry) — closes +INT-01 ↔ INT-02. S1; unblocks INT-05/08/11. The `affinescript-dom-loader` +satellite shell is downstream. |INT-03 |WASI preview2 / host I/O beyond stdout |#180 |S1, ADR-015 ACCEPTED (owner-chosen full WASM Component-Model re-target). Staged S1..S6; legacy preview1 stdout path is the default until S6 diff --git a/docs/TECH-DEBT.adoc b/docs/TECH-DEBT.adoc index 408f0de0..2ae8f133 100644 --- a/docs/TECH-DEBT.adoc +++ b/docs/TECH-DEBT.adoc @@ -158,7 +158,11 @@ 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 |open #179 (blocks INT-05/08/11) +|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 |#180 ADR-015 accepted (full Component-Model re-target, staged S1..S6); S3+ hard-gated on S2 toolchain (`wasm-tools`/`wasm-component-ld`) @@ -177,8 +181,11 @@ fixed; runtime blocked by #255 (wasm loop-codegen defect) |=== |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 |open -(addressed by INT-02) +|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 diff --git a/packages/affine-js/deno.json b/packages/affine-js/deno.json index 3cd2a5db..bf960629 100644 --- a/packages/affine-js/deno.json +++ b/packages/affine-js/deno.json @@ -8,6 +8,9 @@ "./runtime": "./runtime.js" }, "license": "PMPL-1.0-or-later", + "tasks": { + "test": "deno test --allow-read --allow-write loader_test.js" + }, "publish": { "exclude": ["loader_test.js"] } diff --git a/tests/modules/loader-bridge/README.adoc b/tests/modules/loader-bridge/README.adoc new file mode 100644 index 00000000..c4ddeabd --- /dev/null +++ b/tests/modules/loader-bridge/README.adoc @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: PMPL-1.0-or-later += INT-02 loader-bridge acceptance harness (#179) + +Proves the host-agnostic loader (`packages/affine-js/loader.js`) on +*real* compiler-emitted, cross-module wasm — the level above +`packages/affine-js/loader_test.js` (14 unit tests on synthetic bytes, +run via `deno task test` in that package). + +== What it asserts + +`bridge.mjs` uses the **actual loader API** (not a hand-rolled +`Deno.readFile` + manual import object — that is the SAT-02 anti-pattern +the loader replaces, still present by hand in the INT-01 +`tests/modules/xmod-link` harness; this closes INT-01 ↔ INT-02): + +* `readBytes` loads both compiled fixtures host-agnostically; +* `buildImportObject` wires the genuine `CrossCallee` cross-module + namespace INT-01/#178 emits (multi-namespace, not `env`-only); +* the linked `caller.main()` returns `42` across the wasm boundary; +* `parseOwnershipSection` reads a real ownership entry (a Linear param + for `consume(own x: Int)`) from compiler-emitted wasm — the typed-wasm + contract carrier, exercised on genuine output. + +== Run + +[source,sh] +---- +dune build bin/main.exe +./run.sh # deno on PATH, or $AFFINESCRIPT_DENO +---- + +Exit 0 + `PASS:` line = INT-02 substrate proven. Reproducible; kept out +of the hermetic OCaml gate by design (needs a wasm engine + deno), +exactly like `tests/modules/xmod-link`. + +== Note + +WASI is host-supplied as a whole catch-all namespace. `buildImportObject` +*spreads* module members (to merge, not clobber), so a catch-all `Proxy` +is attached directly as `wasi_snapshot_preview1` rather than via the +spread — mirroring real usage: the host owns wasi, the loader owns the +affine runtime + cross-module namespaces. diff --git a/tests/modules/loader-bridge/bridge.mjs b/tests/modules/loader-bridge/bridge.mjs new file mode 100644 index 00000000..ac0c1341 --- /dev/null +++ b/tests/modules/loader-bridge/bridge.mjs @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: PMPL-1.0-or-later +// INT-02 / #179 — host-agnostic loader bridge, end-to-end acceptance. +// +// Proves the *actual* INT-02 loader API (packages/affine-js/loader.js) +// drives genuine compiler-emitted, cross-module wasm — not synthetic +// bytes (loader_test.js does the unit level) and not a hand-rolled +// `Deno.readFile` + manual import object (that is the SAT-02 anti-pattern +// the loader exists to replace; the INT-01 xmod-link harness still does it +// by hand — this closes INT-01 ↔ INT-02). +// +// callee.wasm ← module CrossCallee; pub fn consume(own x: Int) -> Int { x } +// caller.wasm ← use CrossCallee::{consume}; pub fn main() -> Int { consume(42) } +// +// Usage: deno run --allow-read=