- call: use make-symbol for fn name, rest-rest for args (was string + nth)
- on: extract (ref ...) nodes from body as event.detail let-bindings
- host-set!: add ListRef+Number case for array index mutation
- append!: support index 0 for prepend
- hs-put!: branch on list? for array start/end operations
- hs-reset!: form reset restoring defaultValue/checked/textContent
- 522/793 pass (was 493/754)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- inject_path_name: strip _islands/ convention dirs from path-derived names
- page-functions.sx: fix geography (→ ~geography) and isomorphism (→ ~etc/plan/isomorphic)
- request-handler.sx: rewrite sx-eval-page to call page functions explicitly
via env-get+apply, avoiding provide special form intercepting (provide) calls
- sx_server.ml: set expand-components? on AJAX aser paths so server-side
components expand for the browser (islands stay unexpanded for hydration)
- Rename 19 component references in geography/spreads, geography/provide,
geography/scopes to use path-qualified names matching inject_path_name output
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Parser: skip unit suffix when next ident is a comparison keyword
(starts, ends, contains, matches, is, does, in, precedes, follows).
Fixes "123 starts with '12'" returning "123starts" instead of true.
eval-hs: use hs-compile directly instead of hs-to-sx-from-source with
"return " prefix, which was causing the parser to consume the comparison
as a string suffix.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Removed duplicate one-liner sx-nav-tree (leftover from before refactor)
- Renamed "Semantics" → "Capabilities" in nav tree — direct geography
entry, no subsection
- Added "Where code evaluates" section with three demos:
- Server-side fetch (SSR with io capability)
- Client-side fetch (island with reactive signals)
- Same component both ways (isomorphic evaluation)
- Shows how capabilities abstract over location — same code runs
server or client depending on the evaluation context
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three new documentation pages under Geography > Semantics:
- Capabilities: abstract evaluation contexts, capability primitives,
standard capabilities, why not phases
- Modules: the (use) form, what it enables, semantics
- Eval Rules: machine-readable rule set, sx_explain tool, rule structure
Navigation: semantics-nav-items with 3 entries, linked from geography
nav tree after CEK Machine.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two bugs caused code blocks to render empty across the site:
1. ~docs/code component had parameter named `code` which collided with
the HTML <code> tag name. Renamed to `src` and updated all 57
callers. Added font-mono class for explicit monospace.
2. Batched IO dispatch in ocaml_bridge.py only skipped one leading
number (batch ID) but the format has two (epoch + ID):
(io-request EPOCH ID "name" args...). Changed to skip all leading
numbers so the string name is correctly found. This fixes highlight
and other batchable helpers returning empty results.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The geography page function returned nil instead of the index-content
component, and the index layout was missing the standard doc page wrapper.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Aser serialization: aser-call/fragment now return SxExpr instead of String.
serialize/inspect passes SxExpr through unquoted, preventing the double-
escaping (\" → \\\" ) that broke client-side parsing when aser wire format
was output via raw! into <script> tags. Added make-sx-expr + sx-expr-source
primitives to OCaml and JS hosts.
Binary blob protocol: eval, aser, aser-slot, and sx-page-full now send SX
source as length-prefixed blobs instead of escaped strings. Eliminates pipe
desync from concurrent requests and removes all string-escape round-trips
between Python and OCaml.
Bridge safety: re-entrancy guard (_in_io_handler) raises immediately if an
IO handler tries to call the bridge, preventing silent deadlocks.
Fetch error logging: orchestration.sx error callback now logs method + URL
via log-warn. Platform catches (fetchAndRestore, fetchPreload, bindBoostForm)
also log errors instead of silently swallowing them.
Transpiler fixes: makeEnv, scopePeek, scopeEmit, makeSxExpr added as
platform function definitions + transpiler mappings — were referenced in
transpiled code but never defined as JS functions.
Playwright test infrastructure:
- nav() captures JS errors and fails fast with the actual error message
- Checks for [object Object] rendering artifacts
- New tests: delete-row interaction, full page refresh, back button,
direct load with fresh context, code block content verification
- Default base URL changed to localhost:8013 (standalone dev server)
- docker-compose.dev-sx.yml: port 8013 exposed for local testing
- test-sx-build.sh: build + unit tests + Playwright smoke tests
Geography content: index page component written (sx/sx/geography/index.sx)
describing OCaml evaluator, wire formats, rendering pipeline, and topic
links. Wiring blocked by aser-expand-component children passing issue.
Tests: 1080/1080 JS, 952/952 OCaml, 66/66 Playwright
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Major architectural change: page function dispatch and handler execution
now go through the OCaml kernel instead of the Python bootstrapped evaluator.
OCaml integration:
- Page dispatch: bridge.eval() evaluates SX URL expressions (geography, marshes, etc.)
- Handler aser: bridge.aser() serializes handler responses as SX wire format
- _ensure_components loads all .sx files into OCaml kernel (spec, web adapter, handlers)
- defhandler/defpage registered as no-op special forms so handler files load
- helper IO primitive dispatches to Python page helpers + IO handlers
- ok-raw response format for SX wire format (no double-escaping)
- Natural list serialization in eval (no (list ...) wrapper)
- Clean pipe: _read_until_ok always sends io-response on error
SX adapter (aser):
- scope-emit!/scope-peek aliases to avoid CEK special form conflict
- aser-fragment/aser-call: strings starting with "(" pass through unserialized
- Registered cond-scheme?, is-else-clause?, primitive?, get-primitive in kernel
- random-int, parse-int as kernel primitives; json-encode, into via IO bridge
Handler migration:
- All IO calls converted to (helper "name" args...) pattern
- request-arg, request-form, state-get, state-set!, now, component-source etc.
- Fixed bare (effect ...) in island bodies leaking disposer functions as text
- Fixed lower-case → lower, ~search-results → ~examples/search-results
Reactive islands:
- sx-hydrate-islands called after client-side navigation swap
- force-dispose-islands-in for outerHTML swaps (clears hydration markers)
- clear-processed! platform primitive for re-hydration
Content restructuring:
- Design, event bridge, named stores, phase 2 consolidated into reactive overview
- Marshes split into overview + 5 example sub-pages
- Nav links use sx-get/sx-target for client-side navigation
Playwright test suite (sx/tests/test_demos.py):
- 83 tests covering hypermedia demos, reactive islands, marshes, spec explorer
- Server-side rendering, handler interactions, island hydration, navigation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dedicated page documenting and demonstrating content-addressed
computation. How it works, why it matters, the path to IPFS.
Live demo: counter + name widget with CID generation, history,
and restore-from-CID input.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Hash frozen SX to a content identifier (djb2 → hex). Same state
always produces the same CID. Store by CID, retrieve by CID.
- content-hash: djb2 hash of SX text → hex string
- content-put/get: in-memory content store
- freeze-to-cid: freeze scope → store → return CID
- thaw-from-cid: look up CID → thaw signals
- char-code-at / to-hex primitives for both platforms
- Live demo: counter + name widget, content-address button,
CID display, restore from CID input, CID history
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace raw CEK state serialization with named freeze scopes.
A freeze scope collects signals registered within it. On freeze,
signal values are serialized to SX. On thaw, values are restored.
- freeze-scope: scoped effect delimiter for signal collection
- freeze-signal: register a signal with a name in the current scope
- cek-freeze-scope / cek-thaw-scope: freeze/thaw by scope name
- freeze-to-sx / thaw-from-sx: full SX text round-trip
- cek-freeze-all / cek-thaw-all: batch operations
Also: register boolean?, symbol?, keyword? predicates in both
Python and JS platforms with proper var aliases.
Demo: counter + name input with Freeze/Thaw buttons.
Frozen SX: {:name "demo" :signals {:count 5 :name "world"}}
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Documents and demonstrates serializable CEK state. Type an expression,
step to any point, click Freeze to see the frozen SX. Click Thaw to
resume from the frozen state and get the result.
- New page at /sx/(geography.(cek.freeze))
- Nav entry under CEK Machine
- Interactive island demo with step/run/freeze/thaw buttons
- Documentation: the idea, freeze format, thaw/resume, what it enables
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cache the style element reference in _cssx-style-el so flush-cssx-to-dom
never creates more than one. Previous code called dom-query on every
flush, which could miss the element during rapid successive calls,
creating duplicates.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
A defisland that lets users type an SX expression, step through CEK
evaluation one transition at a time, and see C/E/K registers update
live. Demonstrates that cek-step is pure data->data.
- cek.sx geography: add ~geography/cek/demo-stepper island with
source input, step/run/reset buttons, state display, step history
- platform_js.py: register CEK stepping primitives (make-cek-state,
cek-step, cek-terminal?, cek-value, make-env, sx-serialize) so
island code can access them
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>