- suspense render-dom form: shows fallback while resource loads, swaps
to body content when resource signal resolves
- resource async signal: wraps promise into signal with loading/data/error
dict, auto-transitions on resolve/reject via promise-then
- transition: defers signal writes to requestIdleCallback, sets pending
signal for UI feedback during expensive operations
- Added schedule-idle, promise-then platform functions
- All Phase 2 features now marked Done in status tables
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- :class-map dict toggles classes reactively via classList.add/remove
- :style-map dict sets inline styles reactively via el.style[prop]
- ref/ref-get/ref-set! mutable boxes (non-reactive, like useRef)
- :ref attribute sets ref.current to DOM element after rendering
- portal render-dom form renders children into remote target element
- Portal content auto-removed on island disposal via register-in-scope
- Added #portal-root div to page shell template
- Added stop-propagation and dom-focus platform functions
- Demo islands for all three features on the demo page
- Updated status tables: all P0/P1 features marked Done
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Items with :key attributes are matched by key across renders — existing
DOM nodes are reused, stale nodes removed, new nodes inserted in order.
Falls back to clear-and-rerender without keys.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Effect and computed auto-register disposers with island scope via
register-in-scope; dispose-islands-in called before every swap point
(orchestration.sx) to clean up intervals/subscriptions on navigation.
- Map + deref inside islands auto-upgrades to reactive-list for signal-
bound list rendering. Demo island with add/remove items.
- New :bind attribute for two-way signal-input binding (text, checkbox,
radio, textarea, select). bind-input in adapter-dom.sx handles both
signal→element (effect) and element→signal (event listener).
- Phase 2 plan page at /reactive-islands/phase2 covering input binding,
keyed reconciliation, reactive class/style, refs, portals, error
boundaries, suspense, and transitions.
- Updated status tables in overview and plan pages.
- Fixed stopwatch reset (fn body needs do wrapper for multiple exprs).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New top-level Philosophy section in sx-docs. Moved SX Manifesto and Strange
Loops from Essays, added three new essays: SX and Wittgenstein (language games,
limits of language, fly-bottles), SX and Dennett (real patterns, multiple drafts,
intentional stance), and S-Existentialism (existence precedes essence, bad faith,
the absurd). Updated all cross-references and navigation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Rebuild sx-browser.js with signals spec module (was missing entirely)
- Register signal functions (signal, deref, effect, computed, etc.) as
PRIMITIVES so runtime-evaluated SX code in island bodies can call them
- Add reactive deref detection in adapter-dom.sx: (deref sig) in island
scope creates reactive-text node instead of static text
- Add Island SSR support in html.py (_render_island with data-sx-island)
- Add Island bundling in jinja_bridge.py (defisland defs sent to client)
- Update deps.py to track Island dependencies alongside Component
- Add defisland to _ASER_FORMS in async_eval.py
- Add clear-interval platform primitive (was missing)
- Create four live demo islands: counter, temperature, imperative, stopwatch
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All major plan items are now spec'd and bootstrapped:
- Signal runtime, named stores, event bridge (signals.sx)
- Event bindings :on-click (adapter-dom.sx)
- data-sx-emit processing (orchestration.sx)
- Client hydration + disposal (boot.sx)
- Full JS + Python bootstrapping
Only remaining: keyed list reconciliation (optimization)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- adapter-dom.sx: detect :on-click/:on-submit etc. in render-dom-element
— if attr starts with "on-" and value is callable, wire via dom-listen
- orchestration.sx: add process-emit-elements for data-sx-emit attrs
— auto-dispatch custom events on click with optional JSON detail
- bootstrap_js.py: add processEmitElements RENAME
- Regenerate sx-ref.js with all changes
- Update reactive-islands status table
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- signals.sx: fix has? → has-key?, add def-store/use-store/clear-stores
(L3 named stores), emit-event/on-event/bridge-event (event bridge)
- boot.sx: add sx-hydrate-islands, hydrate-island, dispose-island
for client-side island hydration from SSR output
- bootstrap_js.py: add RENAMES, platform fns (domListen, eventDetail,
domGetData, jsonParse), public API exports for all new functions
- bootstrap_py.py: add RENAMES, server-side no-op stubs for DOM events
- Regenerate sx-ref.js (with boot adapter) and sx_ref.py
- Update reactive-islands status: hydration, stores, bridge all spec'd
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- signals.sx: add def-store/use-store/clear-stores (L3 named stores)
and emit-event/on-event/bridge-event (lake→island DOM events)
- reactive-islands.sx: add event bridge, named stores, and plan pages
- Remove ~plan-reactive-islands-content from plans.sx
- Update nav-data.sx and docs.sx routing accordingly
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- New nav entry in ~sx-main-nav (layouts.sx)
- Nav items: Overview, Demo, Plan link (nav-data.sx)
- Overview page: architecture quadrant, four levels, signal primitives,
island lifecycle, implementation status table with done/todo
- Demo page: annotated code examples for signal+computed+effect, batch,
cleanup, computed chains, defisland, test suite
- defpage routes: /reactive-islands/ and /reactive-islands/<slug>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds optimistic-demo-data, action:add-demo-item, offline-demo-data
to boundary spec. Adds orchestration test spec to in-app test runner
with mocked platform functions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests cover page data cache, optimistic cache update/revert/confirm,
offline connectivity tracking, offline queue mutation, and offline-aware
routing. Registered in test runner with mocked platform functions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Design plan for client-side state via signals and islands — a second
sliding bar (reactivity) orthogonal to the existing isomorphism bar.
Covers signal primitives, defisland, shared state, reactive DOM
rendering, SSR hydration, and spec architecture.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- "Zero-Tooling" → "Tools for Fools"
- "Separation of Concerns" → "Separate your Own Concerns"
- Bold "...and yet." after Carson Gross reference
- Add broken keyboard origin story
- Fix language list (never Lisp)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New essay arguing SX eliminates the entire conventional web toolchain
(bundlers, transpilers, package managers, CSS tools, dev servers, linters,
type checkers, framework CLIs) and that agentic AI replaces the code editor
itself. Links Carson Gross's "Yes, and..." essay with a Zen Buddhism framing
of the write→read→describe progression.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
7c: Client data cache management via element attributes
(sx-cache-invalidate) and response headers (SX-Cache-Invalidate,
SX-Cache-Update). Programmatic API: invalidate-page-cache,
invalidate-all-page-cache, update-page-cache.
7d: Service Worker (sx-sw.js) with IndexedDB for offline-capable
data caching. Network-first for /sx/data/ and /sx/io/, stale-while-
revalidate for /static/. Cache invalidation propagates from
in-memory cache to SW via postMessage.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Moved on-demand CSS delivery protocol from docs/css into /cssx/delivery,
framed as one strategy among several. Removed the CSSX Components plan
(now redundant with the top-level /cssx/ section).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New top-level section in sx-docs: /cssx/ with 6 pages:
- Overview: the idea, what changed, advantages
- Patterns: class mapping, data-driven, style functions, responsive, emitting CSS
- Async CSS: components that fetch/cache CSS before rendering via ~suspense
- Live Styles: SSE/WS examples for real-time style updates (noted as future)
- Comparisons: vs styled-components, CSS Modules, Tailwind, Vanilla Extract
- Philosophy: proof by deletion, the right abstraction level
Also:
- Remove CSSX from specs nav (spec file deleted)
- Fix renderer spec prose (no longer mentions StyleValue)
- Update On-Demand CSS essay summary
- Mark CSSX Components plan as done
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
defpage is already portable: server executes via execute_page(),
client via try-client-route. Add render plan logging to client
routing so console shows boundary decisions on navigation:
"sx:route plan pagename — N server, M client"
Mark Phase 7 (Full Isomorphism) as complete:
- 7a: affinity annotations + render-target
- 7b: page render plans (boundary optimizer)
- 7e: cross-host isomorphic testing (61 tests)
- 7f: universal page descriptor + visibility
7c (optimistic updates) and 7d (offline data) remain as future work.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
61 tests evaluate the same SX expressions on both Python (sx_ref.py)
and JS (sx-browser.js via Node.js), comparing output:
- 37 eval tests (arithmetic, strings, collections, logic, HO forms)
- 24 render tests (elements, attrs, void elements, components, escaping)
All pass — both hosts produce identical results from the same spec.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add page-render-plan to deps.sx: given page source + env + IO names,
computes a dict mapping each needed component to "server" or "client",
with server/client lists and IO dep collection. 5 new spec tests.
Integration:
- PageDef.render_plan field caches the plan at registration
- compute_page_render_plans() called from auto_mount_pages()
- Client page registry includes :render-plan per page
- Affinity demo page shows per-page render plans
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>
Add :affinity :client/:server/:auto annotations to defcomp, with
render-target function combining affinity + IO analysis. Includes
spec (eval.sx, deps.sx), tests, Python evaluator, and demo page.
Fix critical bug: Python SX parser _ESCAPE_MAP was missing \r and \0,
causing bootstrapped JS parser to treat 'r' as whitespace — breaking
all client-side SX parsing. Also add \0 to JS string emitter and
fix serializer round-tripping for \r and \0.
Reserved word escaping: bootstrappers now auto-append _ to identifiers
colliding with JS/Python reserved words (e.g. default → default_,
final → final_), so the spec never needs to avoid host language keywords.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add comparisons with styled-components, CSS Modules, Tailwind, Vanilla
Extract, and Design Tokens. Add example of components emitting <style>
blocks directly. Fix "CSS-agnostic" to "strategy-agnostic" — components
can generate CSS, not just reference existing classes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the existing CSSX plan with a component-based approach where styling
is handled by regular defcomp components that apply classes, respond to data,
and compose naturally — eliminating opaque hash-based class names.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add Complete badge with live demo link to Phase 6 section
- Replace Verification with Demonstration + What to verify sections
- Update Files list: boot.sx spec, bootstrap_js.py, demo files
- Add streaming/suspense and client IO to Current State summary
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server streams HTML shell with ~suspense placeholders immediately,
then sends resolution <script> chunks as async IO completes. Browser
renders loading skeletons instantly, replacing them with real content
as data arrives via __sxResolve().
- defpage :stream true opts pages into streaming response
- ~suspense component renders fallback with data-suspense attr
- resolve-suspense in boot.sx (spec) + bootstrapped to sx-browser.js
- __sxPending queue handles resolution before sx-browser.js loads
- execute_page_streaming() async generator with concurrent IO tasks
- Streaming demo page at /isomorphism/streaming with 1.5s simulated delay
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The SX parser counts \n inside string literals as line breaks, so the
parser's line numbers differ from file line numbers. The naive paren
counter was wrong — the original 8 closing parens was correct.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 5 was solved by IO proxy registration + async DOM renderer +
JavaScript Promises — no continuations needed on the client side.
Continuations remain a prerequisite for Phase 6 (server-side streaming).
Updated plan status: Phases 1-5 complete. Phase 4 moved from Partial.
Renumbered: streaming/suspense is now Phase 6, full iso is Phase 7.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pipeline definitions as .sx files evaluated by a minimal Python runner.
CI primitives (shell-run, docker-build, git-diff-files) are boundary-declared
IO, only available to the runner. Steps are defcomp components composable
by nesting. Fixes pre-existing unclosed parens in isomorphic roadmap section.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>