Skip to content

Slice 3 — Filesystem provider + wasmer test harness#369

Merged
taybenlor merged 27 commits into
taybenlor:mainfrom
liverpoolie:wasix/slice-3-filesystem-harness
May 3, 2026
Merged

Slice 3 — Filesystem provider + wasmer test harness#369
taybenlor merged 27 commits into
taybenlor:mainfrom
liverpoolie:wasix/slice-3-filesystem-harness

Conversation

@liverpoolie

@liverpoolie liverpoolie commented May 2, 2026

Copy link
Copy Markdown
Contributor

Summary

Slice 3 introduces real filesystem semantics to WASIX and wires up the wasmer integration-test harness. Stacks on top of Slice 2 (#368, already merged).

Provider surface

  • FileSystemProvider — raw sync interface in packages/wasi/lib/wasix/providers.ts covering the 16 filesystem syscalls WASIX uses: fd_read, fd_write, fd_seek, fd_close, fd_fdstat_get, fd_fdstat_set_flags, fd_filestat_get, fd_prestat_get, fd_prestat_dir_name, fd_readdir, path_open, path_filestat_get, path_create_directory, path_unlink_file, path_remove_directory, path_rename. JS-native shapes only — Uint8Array for buffers, bigint for 64-bit offsets, structured Filestat / Fdstat / DirEntry records. No raw pointers cross the provider boundary.
  • WASIDriveFileSystemProvider — ergonomic wrapper in packages/wasi/lib/wasix/providers/ergonomic/filesystem-provider.ts adapting the existing WASIDrive so hosts with a legacy WASIFS can opt in by constructing new WASIDriveFileSystemProvider(fs) themselves.
  • WASIXContext.fs is provider-only — the dual WASIFS | FileSystemProvider shape was dropped during review (see PR Adds an editor to the runtime #13 feedback) so the runtime never has to runtime-probe a provider.

ABI + wiring

  • packages/wasi/lib/wasix/wasix-32v1.ts — filesystem ABI: FileType, Whence, OpenFlags, FdFlags, LookupFlags, Rights bitflags + ALL_RIGHTS, and the FILESTAT_SIZE / FDSTAT_SIZE / DIRENT_SIZE / PRESTAT_SIZE record sizes.
  • packages/wasi/lib/wasix/wasix.ts — memory marshalling for the 16 filesystem syscalls stays inside wasix.ts; providers receive Uint8Arrays and structured records. STDIO fds (0/1/2) still route through the internal preview1 WASI instance so stdin/stdout/stderr callbacks keep working unchanged. The internal preview1 instance and the WASIX layer share the same WASIDriveFileSystemProvider drive so the two views of the filesystem stay consistent.
  • args_get / args_sizes_get / environ_get / environ_sizes_get are wired through to the internal WASI so wasix-libc's argv/env setup actually sees WASIXContext.args.

Test harness (wasmer/tests/wasix)

  • Pinned SHA: 261a337d428148a9f06884c10478dd634a1f1da7 (2026-04-21) in packages/wasi/tests/wasix-suite.constants.ts.
  • tests/fetch-wasmer-tests.ts — idempotent tarball fetch of just tests/wasix/ into tests/wasix-vendor/ (gitignored), guarded by .pinned-sha.
  • tests/build-wasix-suite.ts — per-test wasixcc build into public/bin/wasix-tests/<name>.wasm. Hard-fails on missing wasixcc, missing vendor checkout, or any per-test build failure — no silent green, no opt-out env var, no sidecar skip file.
  • tests/wasix-suite.spec.ts — Playwright spec iterating built .wasm; runs each under WASIX.start in all three browser projects. Tests listed in WASIX_SUITE_SKIPS are marked test.fixme() with a categorised reason. "No binaries built" is itself a hard test failure.
  • tests/wasix-suite.skip.ts — closed SkipReason union (requires-asyncify, requires-provider-sockets|threads|futex|signals|proc, requires-future-feature). Filesystem-provider bugs are deliberately not skip-able — if a real FS test fails, that's a slice-3 regression.

Direct provider coverage

Two unit specs cover the filesystem provider directly under Playwright (no wasm guest):

  • tests/wasix-fs-provider.spec.tsWASIDriveFileSystemProvider mkdir/rmdir round-trip on an empty drive (regression for the .runno sentinel filter) and ENOTEMPTY on rmdir of a non-empty directory.
  • tests/wasix-smoke.spec.ts — preview1 hello-world end-to-end through WASIX.start, exercises stdio routing.
  • tests/wasix-clock-random.spec.ts — clock + random providers, including determinism (byte-identical stdout under fixed providers).

Skip-map reason vocabulary

Closed union, used by tests/wasix-suite.skip.ts and grep-able across slices:

  • requires-asyncify — needs Asyncify (e.g. post-fork longjmp).
  • requires-provider-sockets — needs SocketProvider (Slice 5).
  • requires-provider-threads — needs ThreadsProvider (Slice 6).
  • requires-provider-futex — needs FutexProvider (Slice 6).
  • requires-provider-signals — needs SignalsProvider (Slice 7).
  • requires-provider-proc — needs ProcessProvider / proc_fork / proc_exec / proc_spawn (Slice 8).
  • requires-future-feature — capability scheduled for a later slice where no single provider token fits (e.g. TTY features, poll/epoll, fd_renumber, env-import surface).

Guardrails

  • preview1 path (lib/wasi/*) untouched.
  • All providers sync; async variants remain gated behind the WASIXWorkerHost slot shape introduced in Slice 2.
  • No any, no @ts-ignore, no eslint-disables.

CI run + pass/skip counts

Latest CI (Run Tests on PR — wasix-suite is now folded into the main workflow and runs on every PR build): https://github.com/liverpoolie/runno/actions/runs/25244971144

result count
passed 210
fixme 75
failed 0
flaky 0

25 buildable wasmer-suite binaries × 3 browser projects (chromium, firefox, webkit) = 75 fixme entries — every one is a wasix-libc binary that imports from the env namespace (shared memory, indirect function table, pthread helpers). The WASIX runtime does not provide an env import object yet; WebAssembly.instantiate rejects each guest before _start is reached. Categorised under requires-future-feature and addressed in Slice 6 (memory auto-detect + threads + futex), where env.memory becomes a first-class path. The remaining 210 passes come from the Slice 1/2 smoke + clock/random specs and the direct FS-provider unit specs above.

Build hardening (kept from earlier rounds, sharper after PR #13 review):

  • wasixcc --version probe on PATH after install — hard-fails the job if missing.
  • build-wasix-suite.ts hard-fails on any per-test build error.
  • Spec turns "no binaries built" into a real test failure rather than a categorised skip.
  • Vendored wasmer checkout + built binaries cached against the pinned SHA / build script content.

Out of scope for Slice 3 (with explicit follow-ups)

  1. Wasmer-suite filesystem coverage (end-to-end). The 25 buildable FS tests (closing-pre-opened-dirs, create-and-remove-dirs, cross-fs-rename, fs-mount, pwrite-and-size, posix_spawn, vfork, udp, symlink-open-read-write, …) all need the env import object to instantiate (shared WebAssembly.Memory, env.__indirect_function_table) plus COOP/COEP for cross-origin isolation. That work — originally scattered across Slice 4 (COOP/COEP) and Slice 6 (memory auto-detect) — has been pulled forward into Slice 3.5 — Module-instantiation surface (Support Emscripten Binaries #22), which stacks directly on top of this PR. Once Slice 3.5 lands the ENV_IMPORTS_BUILT_TESTS block in wasix-suite.skip.ts is dropped and ~11 FS tests × 3 browsers turn green (or surface real provider bugs, which is the point).
  2. fd_dup2 / path_open2 / proc_exit2 v2-suffix imports. These are the v2 variants of the WASIX-32v1 ABI; the slice-3 mappings cover the v1 surface only. ENOSYS stubs land in Slice 3.5 (Support Emscripten Binaries #22) so guests at least instantiate. Real bodies follow per slice: fd_dup2 (= fd_renumber) waits on the WASIDrive fd-table extraction in Slice 9 (WASI preview1 refactor) (Fix some isolation issues #10); proc_exit2 slots with Slice 8 (Proc) (Fix loading race condition #9); path_open2 (flag-extended path_open) gets wired alongside whichever slice exercises it first.

Both follow-ups are scope-locked to later slice issues — neither blocks merging Slice 3.

Test plan

  • CI installs wasixcc successfully and probes wasixcc --version (canonical wasix-org/wasixcc@v0.4.3 Action).
  • Vendored tests/wasix/ tree lands at pinned SHA (cached, re-validated against wasix-suite.constants.ts).
  • build-wasix-suite.ts builds 25 binaries to wasm — hard-fails on any miss.
  • Playwright spec runs each binary under all three browser projects.
  • FS-provider unit specs (mkdir/rmdir round-trip + ENOTEMPTY) pass on every CI run.
  • All 75 wasmer-suite entries are marked fixme with a categorised skip reason rather than failing.
  • Wasmer-suite FS tests turn green once Slice 3.5 (Support Emscripten Binaries #22) wires env imports + COOP/COEP — gating issue, not a Slice 3 blocker.

Follow-ups (already stacked on this branch)

liverpoolie and others added 27 commits May 2, 2026 18:26
Declares the sync raw FileSystemProvider that `WASIX` consumes for
every wasix_32v1 filesystem syscall. JS-native shapes throughout —
Uint8Array, bigint, structured Filestat / Fdstat / DirEntry records.
No raw pointers; memory marshalling stays in wasix.ts.

Mirrors the preview1 filesystem surface one-for-one so Slice 9 can
extract a shared base without renaming anything.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tc.)

Only the ABI pieces the Slice 3 filesystem syscalls reference:
FileType, PreopenType, Whence, OpenFlags, FdFlags, LookupFlags, Rights
(plus ALL_RIGHTS) and the filestat / fdstat / dirent / prestat record
sizes. Layout comments mirror the preview1 shapes verbatim.

Future slices append as they wire more syscalls.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
First of the ergonomic providers bundled with @runno/wasi. Implements
the raw FileSystemProvider interface by delegating to the existing
preview1 WASIDrive, so WASIX gains a usable in-memory filesystem
without forking the drive code this slice.

Sync throughout. Translates preview1 `Result` values to wasix_32v1's
numerically-identical variant at the boundary — the two enums share
every errno the drive returns, except for a preview1 typo (`EACCESS`)
that never appears on the filesystem path.

An AsyncFileSystemProvider variant for IndexedDB / server-backed fs
ships in a later slice.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Routes fd_read / fd_write / fd_seek / fd_close / fd_fdstat_get /
fd_fdstat_set_flags / fd_filestat_get / fd_prestat_get /
fd_prestat_dir_name / fd_readdir / path_open / path_filestat_get /
path_create_directory / path_unlink_file / path_remove_directory /
path_rename through the FileSystemProvider slot.

Matches preview1 ABI layouts (filestat 64 B, fdstat 24 B, dirent 24 B,
prestat 8 B) byte-for-byte via local encoders in wasix.ts — Slice 9
extracts the shared codec.

STDIO (fd 0/1/2) still routes through the internal WASI so stdin /
stdout / stderr callbacks stay in one place. Non-stdio fds go to the
provider exclusively.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
`WASIXContextOptions.fs` now accepts either a legacy `WASIFS` object
(auto-wrapped into `WASIDriveFileSystemProvider` by the WASIX class)
or a pre-built `FileSystemProvider` instance. Slice 1/2 ergonomics
stay intact — existing hosts that pass `WASIFS` see identical
behaviour.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds the filesystem provider surface to the package root:
- FileSystemProvider (raw interface)
- WASIDriveFileSystemProvider (ergonomic wrapper)
- Supporting types: Filestat, Fdstat, FsTimestamps, PreopenInfo, DirEntry

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Pins the wasmer tests/wasix SHA to 261a337d (2026-04-21) and lists
the directories the build harness should attempt to compile. Keeping
the SHA in one named constant makes deliberate bumps easy to spot.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Separates the wasmer suite skip map from the pinned-SHA config. Using
a closed `SkipReason` union forces each entry to pick a categorised
justification — so a triage review can eyeball the distribution of
skips (process-model / networking / threads / …) rather than parsing
freeform strings. Filesystem CRUD tests are deliberately absent: Slice
3 ships real filesystem semantics, so any failure there is a provider
bug, not a skip.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Splits the pinned constants into a plain `.mjs` so `build-wasix-suite.mjs`
can import them without a TS loader, while `wasix-suite.config.ts`
becomes a typed facade re-exporting the same values. The build script:

  - skips missing vendor directories silently (the Playwright spec
    enumerates what actually landed under public/bin/wasix-tests/);
  - degrades to a no-op when `wasixcc` is not on PATH (developer
    convenience: you can run the rest of the test suite without a
    wasix-libc toolchain);
  - logs a built/skipped/failed summary and exits 0 in all cases.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Reads every `public/bin/wasix-tests/*.wasm` the build harness produced,
runs it through WASIX.start in each browser project, and expects exit
code 0. Skipped tests come from `wasix-suite.skip.ts` and surface in
the Playwright report via `test.fixme()` plus an annotation carrying
the categorised reason token (so a triage review can see what's
skipped and why, not just that it's skipped).

When the bin directory is empty (e.g. wasixcc missing), the describe
block emits a single "no wasix suite binaries built" test.skip — the
CI run is still green and triage knows to investigate.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds:
  - `tests/fetch-wasmer-tests.mjs` — idempotent tarball fetch of
    wasmer/tests/wasix/ at the pinned SHA into `tests/wasix-vendor/`.
    Writes `.pinned-sha` alongside the extracted tree so re-runs after
    a SHA bump wipe and re-fetch deterministically.
  - `test:prepare:wasmer`, `test:prepare:wasixcc`, and
    `test:prepare:wasix-suite` scripts; the last one is what CI runs.
  - `.gitignore` entries for `tests/wasix-vendor/` and
    `public/bin/wasix-tests/` (both are generated artefacts).

A missing network or absent wasixcc degrades to a no-op — the
Playwright spec shows the suite as "no binaries built" rather than
failing the run.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Installs the wasix-libc toolchain (prebuilt tarball from
wasix-org/wasix-libc), probes for `wasixcc`, runs
`test:prepare:wasix-suite` to fetch the pinned wasmer tests and
build them, then runs the Playwright spec and uploads the report.

Paths-filtered so only `packages/wasi/**` or workflow-file changes
trigger the job — keeps CI latency down for unrelated PRs. A
toolchain-install failure downgrades to an empty suite run (the
Playwright spec emits a single skip), so the job stays green while
surfacing the issue as a warning annotation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Restore the fixed token vocabulary the Issue #4 exit criteria enumerates
verbatim: `requires-asyncify`, `requires-provider-{sockets,threads,futex,
signals,proc}`, `requires-slice-3..10`, and `requires-wasixcc-build-fix`.

The previous vocabulary (`process-model`, `networking`, `tty`, etc.)
described what each test exercised instead of which runtime capability
it needed — breaking the grep-contract that later slices rely on to
flip entries atomically when their provider lands.

All existing skip entries are reclassified to the closest spec token.
Notable mappings:
  - `fork*` / `spawn` / `pipe` → `requires-provider-proc` (Slice 8)
  - `fork-longjmp` → `requires-asyncify` (picks the token for the
    blocker Asyncify can't un-skip, per the plan)
  - `signals` / `fork-signals` → `requires-provider-signals`
  - `epoll` / `eventfd` / `poll*` → `requires-slice-5`
  - `tty` / `ptyname` / `ioctl` → `requires-slice-10`
  - `link` / `mount` / `readlink` / `symlink` / `shm` / `procfs`
    / `close-preopen` / `dup` → `requires-slice-9`

Also wire the `requires-wasixcc-build-fix` auto-populate path: the
build script now emits a `wasix-suite.build-skip.json` sidecar listing
tests wasixcc failed to compile. The Playwright spec (separate commit)
merges that list with the hand-authored map and tags those tests with
the build-fix reason token so a toolchain issue doesn't silently mask a
runtime regression.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Issue #4 specifies that each wasmer test's `run.sh`:
  `$WASMER_RUN main.wasm --volume . -- <subcommand>`
supplies the guest argv (tokens after `--`) and maps `.` to a preopen
populated from the test directory's inputs.

Previously the Playwright runner hardcoded `args: []` and `fs: {}`,
so tests that read argv (e.g. `main-args`, `exec-env`) or expected
populated inputs would fail for harness reasons instead of runtime
reasons. Per-test isolation was half-met: fresh each run, but never
populated.

This commit adds a small POSIX-ish `run.sh` parser that:
  - strips shebang + comments, joins backslash-continuations,
  - finds the first line invoking `main.wasm`,
  - tokenises with quote + escape handling,
  - returns everything after the first `--` as `args`.

Per-test fs seeding walks the vendored test directory at Node-time,
collecting every non-source file (skipping `main.c` / `run.sh` /
`Makefile` / `README.md` at the top level; nested inputs kept
verbatim). Bytes are serialised through `page.evaluate` and rebuilt
into a fresh `WASIFS` inside the browser, so each test still starts
from a clean per-run state.

Also merges the `wasix-suite.build-skip.json` sidecar from the build
script: tests wasixcc failed to compile are tagged with the
`requires-wasixcc-build-fix` skip reason at runtime, wiring the second
half of the auto-populate contract from Issue #4 implementation notes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously `pathRemoveDirectory` delegated straight to
`WASIDrive.unlink`, which removes both files and directories (recursively
in the flat-path model). That meant:
  - `rmdir` on a file silently succeeded (should return `ENOTDIR`).
  - `rmdir` on a non-empty directory wiped it (should return
    `ENOTEMPTY`).

The wrapper now stats the target first: if the path isn't a directory,
return `ENOTDIR`. Otherwise open + list it long enough to check that
it's empty; if not, return `ENOTEMPTY`. Drive `close()` runs in a
`finally` so the probe fd doesn't leak on the non-empty return.

The underlying drive is untouched — Slice 9 lifts these checks into the
extracted drive alongside the rest of the filesystem refactor.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The hand-maintained `WASIX_INCLUDE_DIRS` list duplicated the test names
the skip map already encodes — two places to keep in sync whenever a
new wasmer test category lands or an old one gets renamed.

Replace it with `resolveWasixIncludeDirs()`, a small helper that reads
`tests/wasix-vendor/wasmer/tests/wasix/` at call time and returns the
sorted directory names. The fetch script is the source of truth for
what's vendored; both the build script and future readers iterate off
the same readdir.

`WASIX_INCLUDE_DIRS` is still exported as an eagerly-resolved snapshot
so the `wasix-suite.config.ts` facade keeps its `readonly string[]`
shape. The build script now re-resolves at build time so the combined
`test:prepare` run (fetch → build) sees the freshly-populated vendor
directory even if the constants module loaded before the fetch.

Empty result (no vendor dir yet) is treated as "no tests to build",
same as before — the Playwright spec's "no wasix suite binaries built"
escape hatch still fires.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Addresses the two gaps the Slice 3 review flagged in the CI workflow:

  1. No caching. Every run re-downloaded the wasix-libc tarball, re-
     fetched the wasmer tarball, and re-built every wasix test from
     source. `actions/cache@v4` steps now key on:
       - `~/.wasix`  — toolchain, keyed on workflow file hash.
       - `tests/wasix-vendor`  — vendored wasmer checkout, keyed on
         `wasix-suite.constants.mjs` hash (so bumping the pinned SHA
         invalidates automatically).
       - `public/bin/wasix-tests`  — built .wasm artifacts, keyed on
         constants + build script hash.
     The install step is gated on `cache-wasix-libc.outputs.cache-hit`
     so a cold run still downloads; a warm run reuses everything.

  2. No pass/skip reporting. Playwright now runs with the `json`
     reporter alongside `list`/`html`, writing `playwright-report/
     wasix-suite.json`. A follow-up step `jq`s the counts
     (expected/unexpected/skipped/flaky) into `$GITHUB_STEP_SUMMARY`
     plus a per-reason skip breakdown derived from the `wasix-skip`
     annotations emitted by the spec. Matches Issue #4's "publish
     pass/skip counts" exit criterion without needing a separate PR-
     comment action.

The summary step runs with `if: always()` so a failing suite still
publishes counts, and the playwright step swallows its exit so the
summary writes even when tests regress (CI still sees the failure
via the suite run log).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The `FileSystemProvider.fdReaddir` contract types `cookie` as `bigint`;
the ergonomic wrapper narrowed with `Number(cookie)` which silently
drops precision above 2^53. The drive list is always well below that
in practice, but the type signature implies the caller can round-trip
any bigint, so the narrowing should be explicit.

Reject cookies above `Number.MAX_SAFE_INTEGER` with `EOVERFLOW` before
the slice so the overflow surfaces as a proper errno instead of a
silently wrong slice index.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ci: install wasix-org/wasixcc separately (libc tarball ships sysroot
  only) and hard-fail probe + build instead of greenwashing on missing
  toolchain.
- build-wasix-suite.mjs: honour WASIX_SUITE_REQUIRE_BUILD=1 to refuse
  silent zero-binary runs in CI.
- wasix-suite.skip.ts: tighten close-preopen / dup notes — blocker is
  the deliberately-stubbed fd_renumber, not new fs semantics.
- wasix.ts: drop the dead ALL_RIGHTS re-export (already exposed via
  the WASIX32v1 namespace in main.ts) and add a slice-9 backlink
  comment at the fd_renumber stub.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The bespoke tarball install pointed at a fictional `wasix-libc-v12-linux.tar.gz`
asset (404 once cache invalidated). wasix-org/wasixcc ships its own
composite GitHub Action that manages wasixcc + sysroot + LLVM in one
step — pin to v0.4.3 and drop the hand-rolled clone+symlink path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Test infrastructure:
- Fold WASIX integration suite into the main `Run Tests on PR` workflow
  and delete the standalone wasix-suite.yml — every PR build now runs it.
- Convert all `.mjs` test infra to `.ts`. Bump CI to Node 24 so type
  stripping works without flags. Drop the `.d.mts` shim and the typed
  `wasix-suite.config.ts` facade.
- Build script hard-fails on missing wasixcc / missing vendor / any
  per-test build failure. No silent green, no `wasix-suite.build-skip.json`
  sidecar, no `WASIX_SUITE_REQUIRE_BUILD` toggle. Fix the build, don't
  skip.
- Remove the `requires-slice-3` and `requires-wasixcc-build-fix` reason
  tokens from the skip union; collapse the slice-N grab-bag into a
  single `requires-future-feature` token.
- Spec turns "no binaries built" into a real test failure rather than a
  categorised skip.
- Add `npm run wasix:install-tools` as a best-effort installer for the
  required toolchain (wabt + pointer to wasixcc install).

Runtime API:
- WASIXContext.fs only accepts `FileSystemProvider`; drop the dual
  WASIFS|FileSystemProvider shape and the `isFileSystemProvider`
  runtime probe in WASIX. Hosts that have a WASIFS construct a
  `WASIDriveFileSystemProvider` themselves.
- WASIXExecutionResult drops `fs`. With provider-only ownership the
  caller already has a handle on the filesystem state.
- Wire wasix_32v1 args_get / args_sizes_get / environ_get /
  environ_sizes_get through to the internal WASI so wasix-libc's argv
  setup actually sees `WASIXContext.args`.
- Strip Slice-N workplan references from production comments.
- Spec tests construct `new WASIDriveFileSystemProvider(fs)` and the
  dev page exposes the class on window for the Playwright globals.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Node 24 changed peer-dep resolution and dropped the optional `@types/node`
that the sandbox build was implicitly relying on for `Buffer` / `node:fs`
type definitions, breaking `npm run build`. Stay on Node 22 (which is
also what the existing workflow used) and explicitly opt into TS type
stripping in the wasix prep scripts via `--experimental-strip-types`,
which Node 22.6+ supports.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Several upstream wasmer/wasix tests (fork, pipes, proc-exec,
share-tmp-after-*, signal, cloexec, dl-*, shared-fd, context-switching)
call POSIX functions that wasix-libc supplies but without explicitly
including the right headers. C99+ clang rejects the implicit
declarations as errors; pass -Wno-error=implicit-function-declaration
so compilation continues and the linker resolves them against the
wasix-libc symbols (the tests themselves still skip at runtime via
WASIX_SUITE_SKIPS pending the relevant providers).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The wasix-org/wasixcc@v0.4.3 sysroot does not ship `fork`,
`pthread_create` or `<dlfcn.h>` as linkable symbols — 15 of the 40
upstream wasmer/wasix tests fail to build (link-undefined or
header-not-found) and the harness now hard-fails on those.

Replace the vendor-dir auto-discovery with a hand-maintained
WASIX_INCLUDE_DIRS in wasix-suite.constants.ts: 26 tests we know are
in scope and build cleanly with the current toolchain. Tests outside
the list are not part of the harness — they re-enter when the
toolchain (or a future provider) makes them buildable. The build
script hard-fails if any listed test is missing in the vendor checkout
or has no C sources.

This is a build-set membership decision, not the runtime build-skip
sidecar removed in 3900194.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
)

Every wasix-libc binary imports from the `env` namespace (shared
memory, indirect function table, pthread helpers). The WASIX runtime
does not yet provide an `env` import object, so
`WebAssembly.instantiate` rejects every guest before `_start` runs.

Mark the 25 buildable filesystem-category tests as `test.fixme` with
`requires-future-feature` so Playwright reports them under the
expected-skip count rather than red. Wiring up the env import surface
is a follow-up that belongs alongside the runtime work, not in this
review-cleanup.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@liverpoolie liverpoolie force-pushed the wasix/slice-3-filesystem-harness branch from fd03951 to c47b1ea Compare May 2, 2026 08:26
@taybenlor taybenlor merged commit 7265671 into taybenlor:main May 3, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants