- cek_run patched to handle import suspensions via _import_hook.
define-library (import ...) now resolves cleanly on the server.
IO suspension errors: 190 → 0. JIT failures: ~50 → 0.
- _import_hook wired in sx_server.ml to load .sx files on demand.
- compile-modules.js syncs source .sx files to dist/sx/ before
compiling — eliminates stale bytecode from out-of-date copies.
- WASM binary rebuilt with all fixes.
- 2658/2658 tests pass (8 new — previously failing import tests).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When the VM or CEK hits an undefined symbol, it checks a symbol→library
index (built from manifest exports at boot), loads the library that
exports it, and returns the value. Execution continues as if the module
was always loaded. No import statements, no load-library! calls, no
Suspense boundaries — just call the function.
This is the same mechanism as IO suspension for data fetching. The
programmer doesn't distinguish between calling a local function and
calling one that needs its module fetched first. The runtime treats
code as just another resource.
Implementation:
- _symbol_resolve_hook in sx_types.ml — called by env_get_id (CEK path)
and vm_global_get (VM path) when a symbol isn't found
- Symbol→library index built from manifest exports in sx-platform.js
- __resolve-symbol native calls __sxLoadLibrary, module loads, symbol
appears in globals, execution resumes
- compile-modules.js extracts export lists into module-manifest.json
- Playground page demonstrates: (freeze-scope) triggers freeze.sxbc
download transparently on first use
2650/2650 tests pass.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bytecode compiler now emits OP_PERFORM for (import ...) and compiles
(define-library ...) bodies. The VM stores the import request in
globals["__io_request"] and stops the run loop — no exceptions needed.
vm-execute-module returns a suspension dict, vm-resume-module continues.
Browser: sx_browser.ml detects suspension dicts from execute_module and
returns JS {suspended, op, request, resume} objects. The sx-platform.js
while loop handles cascading suspensions via handleImportSuspension.
13 modules load via .sxbc bytecode in 226ms (manifest-driven), both
islands hydrate, all handlers wired. 2650/2650 tests pass including
6 new vm-import-suspension tests.
Also: consolidated sx-platform-2.js → sx-platform.js, fixed
vm-execute-module missing code-from-value call, fixed bootstrap.py
protocol registry transpiler issues.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
All 26 browser modules recompiled with define-library/import forms.
Compilation works without vm-compile-adapter (JIT pre-compilation
hangs with library wrappers in some JIT paths — skipped for now,
CEK compilation is ~34s total).
Key fixes:
- eval command: import-aware loop that handles define-library/import
locally without touching the Python bridge pipe (avoids deadlock)
- compile-modules.js: skip vm-compile-adapter, bump timeout
2621/2621 OCaml tests passing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
sx_server.ml: the "eval" command now uses cek_run_with_io instead of
raw eval_expr. This handles import suspensions during eval-blob
(needed for .sx files with define-library/import wrappers).
compile-modules.js: timeout bumped 5min → 10min for sxbc compilation
with define-library overhead.
2608/2608 tests passing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Phase 1 Step 1 of the architecture roadmap. The old cssx.sx
(cssx-resolve, cssx-process-token, cssx-template, old tw function)
is superseded by the ~tw component system in tw.sx.
- Delete shared/sx/templates/cssx.sx
- Remove cssx.sx from all load lists (sx_server.ml, run_tests.ml,
mcp_tree.ml, compile-modules.js, bundle.sh, sx-build-all.sh)
- Replace (tw "tokens") inline style calls with (~tw :tokens "tokens")
in layouts.sx and not-found.sx
- Remove _css-hash / init-css-tracking / SX-Css header plumbing
(dead code — ~tw/flush + flush-collected-styles handle CSS now)
- Remove sx-css-classes param and meta tag from shell template
- Update stale data-cssx references to data-sx-css in tests
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
signal-add-sub! used (append! subscribers f) which returns a new list
for immutable List but discards the result — after signal-remove-sub!
replaces the subscribers list via dict-set!, re-adding subscribers
silently fails. Counter island only worked once (0→1 then stuck).
Fix: use (dict-set! s "subscribers" (append ...)) to explicitly update
the dict field, matching signal-remove-sub!'s pattern.
Build pipeline fixes:
- sx-build-all.sh now bundles spec→dist and recompiles .sxbc bytecode
- compile-modules.js syncs .sx source files alongside .sxbc to wasm/sx/
- Per-file cache busting: wasm, platform JS, and sxbc each get own hash
- bundle.sh adds cssx.sx to dist
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
JIT compiler:
- Fix jit_compile_lambda: resolve `compile` via symbol lookup in env
instead of embedding VmClosure in AST (CEK dispatches differently)
- Register eval-defcomp/eval-defisland/eval-defmacro runtime helpers
in browser kernel for bytecoded defcomp forms
- Disable broken .sxbc.json path (missing arity in nested code blocks),
use .sxbc text format only
- Mark JIT-failed closures as sentinel to stop retrying
CSSX in browser:
- Add cssx.sx symlink + cssx.sxbc to browser web stack
- Add flush-cssx! to orchestration.sx post-swap for SPA nav
- Add cssx.sx to compile-modules.js and mcp_tree.ml bytecode lists
SPA navigation:
- Fix double-fetch: check e.defaultPrevented in click delegation
(bind-event already handled the click)
- Fix layout destruction: change nav links from outerHTML to innerHTML
swap (outerHTML destroyed #main-panel when response lacked it)
- Guard JS popstate handler when SX engine is booted
- Rename sx-platform.js → sx-platform-2.js to bust immutable cache
Playwright tests:
- Add trackErrors() helper to all test specs
- Add SPA DOM comparison test (SPA nav vs fresh load)
- Add single-fetch + no-duplicate-elements test
- Improve MCP tool output: show failure details and error messages
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rewrite compile-modules.js to use the native OCaml sx_server binary
instead of the js_of_ocaml kernel in Node.js. Compiles 23 modules in
23s (was 3+ minutes). Uses batch epoch protocol with latin1 encoding
to preserve byte positions for multi-byte UTF-8 content.
- Add compile-blob server command: parse source natively, compile via
SX compile-module, return bytecode dict
- Fix orchestration.sxbc.json and boot.sxbc.json — never compiled
successfully with the old JS kernel, now work with native compiler
- Auto-copy compiled bytecode to shared/static/wasm/sx/ for serving
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bytecode modules are now serialized as s-expressions (.sxbc) in addition
to JSON (.sxbc.json). The .sxbc format is the canonical representation —
content-addressable, parseable by the SX parser, and suitable for CID
referencing. Annotation layers (source maps, variable names, tests, docs)
can reference the bytecode CID without polluting the bytecode itself.
Format: (sxbc version hash (code :arity N :bytecode (...) :constants (...)))
The browser loader tries .sxbc first (via load-sxbc kernel primitive),
falls back to .sxbc.json. Caddy needs .sxbc MIME type to serve the new
format (currently 404s, JSON fallback works).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- sx_browser.ml: add api_load_module (execute pre-compiled bytecode on VM,
copy defines back to env) and api_compile_module (compile SX source to
bytecode via compile-module function)
- compile-modules.js: Node.js build tool that loads the js_of_ocaml kernel,
compiles all 23 .sx platform files to bytecode, writes .sxbc.json files
- Serialization format: type-tagged JSON constants (s/n/b/nil/sym/kw/list/code)
with nested code objects for lambda closures
All 23 files compile successfully (430K total bytecode JSON).
Next: wire up sx-platform.js to load bytecode instead of source.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>