- Add `scope` special form to eval.sx: (scope name body...) or
(scope name :value v body...) — general dynamic scope primitive
- `provide` becomes sugar: (provide name value body...) calls scope
- Rename provide-push!/provide-pop! to scope-push!/scope-pop! throughout
all adapters (async, dom, html, sx) and platform implementations
- Update boundary.sx: Tier 5 now "Scoped effects" with scope-push!/
scope-pop! as primary, provide-push!/provide-pop! as aliases
- Add scope form handling to async adapter and aser wire format
- Update sx-browser.js, sx_ref.py (bootstrapped output)
- Add scopes.sx docs page, update provide/spreads/demo docs
- Update nav-data, page-functions, docs page definitions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Spreads now emit their attrs into the nearest element's provide scope
instead of requiring per-child spread? checks at every intermediate
layer. emit! is tolerant (no-op when no provider), so spreads in
non-element contexts silently vanish.
- adapter-html: element/lake/marsh wrap children in provide, collect
emitted; removed 14 spread filters from fragment, forms, components
- adapter-sx: aser wraps result to catch spread values from fn calls;
aser-call uses provide with attr-parts/child-parts ordering
- adapter-async: same pattern for both render and aser paths
- adapter-dom: added emit! in spread dispatch + provide in element
rendering; kept spread? checks for reactive/island and DOM safety
- platform: emit! returns NIL when no provider instead of erroring
- 3 new aser tests: stored spread, nested element, silent drop
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Four new primitives for scoped downward value passing and upward
accumulation through the render tree. Specced in .sx, bootstrapped
to Python and JS across all adapters (eval, html, sx, dom, async).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New SX primitives for child-to-parent communication in the render tree:
- spread type: make-spread, spread?, spread-attrs — child injects attrs
onto parent element (class joins with space, style with semicolon)
- collect!/collected/clear-collected! — render-time accumulation with
dedup into named buckets
~cssx/tw is now a proper defcomp returning a spread value instead of a
macro wrapping children. ~cssx/flush reads collected "cssx" rules and
emits a single <style data-cssx> tag.
All four render adapters (html, async, dom, aser) handle spread values.
Both bootstraps (Python + JS) regenerated. Also fixes length→len in
cssx.sx (length was never a registered primitive).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
Two bugs fixed:
1. process-bindings used merge(env) which returns {} for Env objects
(Env is not a dict subclass). Changed to env-extend in render.sx
and adapter-async.sx. This caused "Undefined symbol: theme" etc.
2. async-aser-eval-call passed evaled-args list to async-invoke(&rest),
double-wrapping it. Changed to inline apply + coroutine check.
Also: bootstrap define-async into sx_ref.py (Phase 6), replace ~1000 LOC
hand-written async_eval_ref.py with 24-line thin re-export shim.
Test runner now uses Env (not flat dict) for render envs to catch scope bugs.
8 new regression tests (4 scope chain, 2 native callable arity, 2 render).
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>
Islands survive hypermedia swaps: morph-node skips hydrated
data-sx-island elements when the same island exists in new content.
dispose-islands-in skips hydrated islands to prevent premature cleanup.
- @client directive: .sx files marked ;; @client send define forms to browser
- CSSX client-side: cssxgroup renamed (no hyphen) to avoid isRenderExpr
matching it as a custom element — was producing [object HTMLElement]
- Island wrappers: div→span to avoid block-in-inline HTML parse breakage
- ~sx-header is now a defisland with inline reactive colour cycling
- bootstrap_js.py defaults output to shared/static/scripts/sx-browser.js
- Deleted stale sx-ref.js (sx-browser.js is the canonical browser build)
- Hegelian Synthesis essay: dialectic of hypertext and reactivity
- component-source helper handles Island types for docs pretty-printing
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>
The entire parallel CSS system (StyleValue type, style dictionary,
keyword atom resolver, content-addressed class generation, runtime
CSS injection, localStorage caching) was built but never adopted —
the codebase already uses :class strings with defcomp components
for all styling. Remove ~3,000 lines of unused infrastructure.
Deleted:
- cssx.sx spec module (317 lines)
- style_dict.py (782 lines) and style_resolver.py (254 lines)
- StyleValue type, defkeyframes special form, build-keyframes platform fn
- Style dict JSON delivery (<script type="text/sx-styles">), cookies, localStorage
- css/merge-styles primitives, inject-style-value, fnv1a-hash platform interface
Simplified:
- defstyle now binds any value (string, function) — no StyleValue type needed
- render-attrs no longer special-cases :style StyleValue → class conversion
- Boot sequence skips style dict init step
Preserved:
- tw.css parsing + CSS class delivery (SX-Css headers, <style id="sx-css">)
- All component infrastructure (defcomp, caching, bundling, deps)
- defstyle as a binding form for reusable class strings
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>