Phase 6 — deftype: named type aliases, unions, records, and parameterized
types. Type definitions stored as plain dicts in *type-registry*. Includes
resolve-type for named type resolution, substitute-type-vars for
parameterized instantiation, subtype-resolved? for structural record
subtyping, and infer-type extension for record field type inference via get.
Phase 7 — defeffect: static effect annotations. Effects stored in
*effect-registry* and *effect-annotations*. Supports :effects keyword on
defcomp and define. Gradual: unannotated = all effects, empty list = pure.
check-body-walk validates effect containment at call sites.
Standard types defined: (maybe a), type-def, diagnostic, prim-param-sig.
Standard effects declared: io, mutation, render.
84/84 type system tests pass. Both Python and JS bootstrappers succeed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extend the type annotation system from defcomp-only to fn/lambda params:
- Infrastructure: sf-lambda, py/js-collect-params-loop, and bootstrap_py.py
now recognize (name :as type) in param lists, extracting just the name
- bootstrap_py.py: add _extract_param_name() helper, fix _emit_for_each_stmt
- 521 type annotations across 22 .sx spec files (eval, types, adapters,
transpilers, engine, orchestration, deps, signals, router, prove, etc.)
- Zero behavioral change: annotations are metadata for static analysis only
- All bootstrappers (Python, JS, G1) pass, 81/81 spec tests pass
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The sync aser-call in adapter-sx.sx didn't flatten list results from
map/filter in positional children — serialize(list) wrapped in parens
creating ((div ...) ...) which re-parses as an invalid call. Rewrote
aser-call from reduce to for-each (bootstrapper can't nest for-each
inside reduce lambdas) and added list flattening in both aser-call
and aser-fragment.
Also adds test-aser.sx (41 tests), render-sx platform function,
expanded test-render.sx (+7 map/filter children tests), and specs
async-eval-slot-inner in adapter-async.sx.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
eval-list only dispatches to the render adapter when render-active? is true.
render-to-html and aser set render-active! on entry. Pure evaluate() calls
no longer stringify component results through the render adapter.
Fixes component children parity: (defcomp ~wrap (&key &rest children) children)
now returns [1,2,3] in eval mode, renders to "123" only in render mode.
Parity: 112/116 pass (remaining 4 are hand-written evaluator.py bugs).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Rename /reactive-islands/ → /reactive/, /reference/ → /hypermedia/reference/,
/examples/ → /hypermedia/examples/ across all .sx and .py files
- Add 404 error page (not-found.sx) working on both server refresh and
client-side SX navigation via orchestration.sx error response handling
- Add trailing slash redirect (GET only, excludes /api/, /static/, /internal/)
- Remove blue sky-500 header bar from SX docs layout (conditional on header-rows)
- Fix 405 on API endpoints from trailing slash redirect hitting POST/PUT/DELETE
- Fix client-side 404: orchestration.sx now swaps error response content
instead of silently dropping it
- Add new plan files and home page component
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Lake tag (lake :id "name" children...) creates server-morphable slots
within islands. During morph, the engine enters hydrated islands and
updates data-sx-lake elements by ID while preserving surrounding
reactive DOM (signals, effects, event listeners).
Specced in .sx, bootstrapped to JS and Python:
- adapter-dom.sx: render-dom-lake, reactive-attr marks data-sx-reactive-attrs
- adapter-html.sx: render-html-lake SSR output
- adapter-sx.sx: lake serialized in wire format
- engine.sx: morph-island-children (lake-by-ID matching),
sync-attrs skips reactive attributes
- ~sx-header uses lakes for logo and copyright
- Hegelian essay updated with lake code example
Also includes: lambda nil-padding for missing args, page env ordering fix
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three bugs prevented islands from working during SX wire navigation:
1. components_for_request() only bundled Component and Macro defs, not
Island defs — client never received defisland definitions during
navigation (components_for_page for initial HTML shell was correct).
2. hydrate-island used morph-children which can't transfer addEventListener
event handlers from freshly rendered DOM to existing nodes. Changed to
clear+append so reactive DOM with live signal subscriptions is inserted
directly.
3. asyncRenderToDom (client-side async page eval) checked _component but
not _island on ~-prefixed names — islands fell through to generic eval
which failed. Now delegates to renderDomIsland.
4. setInterval_/setTimeout_ passed SX Lambda objects directly to native
timers. JS coerced them to "[object Object]" and tried to eval as code,
causing "missing ] after element list". Added _wrapSxFn to convert SX
lambdas to JS functions before passing to timers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New spec file signals.sx defines the signal runtime: signal, computed,
effect, deref, reset!, swap!, batch, dispose, and island scope tracking.
eval.sx: defisland special form + island? type predicate in eval-call.
boundary.sx: signal primitive declarations (Tier 3).
render.sx: defisland in definition-form?.
adapter-dom.sx: render-dom-island with reactive context, reactive-text,
reactive-attr, reactive-fragment, reactive-list helpers.
adapter-html.sx: render-html-island for SSR with data-sx-island/state.
adapter-sx.sx: island? handling in wire format serialization.
special-forms.sx: defisland declaration with docs and example.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Split monolithic render.sx into core (tag registries, shared utils) plus
four adapter .sx files: adapter-html (server HTML strings), adapter-sx
(SX wire format), adapter-dom (browser DOM nodes), and engine (SxEngine
triggers, morphing, swaps). All adapters written in s-expressions with
platform interface declarations for JS bridge functions.
Bootstrap compiler now accepts --adapters flag to emit targeted builds:
-a html → server-only (1108 lines)
-a dom,engine → browser-only (1634 lines)
-a html,sx → server with SX wire (1169 lines)
(default) → all adapters (1800 lines)
Fixes: keyword arg i-counter desync in reduce across all adapters,
render-aware special forms (let/if/when/cond/map) in HTML adapter,
component children double-escaping, ~prefixed macro dispatch.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>