Commit Graph

26 Commits

Author SHA1 Message Date
53eab66a90 Add Content Addressing page under CEK Machine
Some checks failed
Build and Deploy / build-and-deploy (push) Has been cancelled
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>
2026-03-15 00:23:25 +00:00
f7debec7c6 Content-addressed computation: freeze → hash → CID → thaw
Some checks failed
Build and Deploy / build-and-deploy (push) Has been cancelled
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>
2026-03-15 00:17:29 +00:00
488fc53fda Persist home stepper state to localStorage via freeze scope
Some checks failed
Build and Deploy / build-and-deploy (push) Has been cancelled
- freeze-scope "home-stepper" captures step-idx signal
- Each step/back saves to localStorage via freeze-to-sx
- On mount, restores from localStorage via thaw-from-sx
- Invalid state resets to default (step 9)
- Clear preview lake before replay to prevent duplicates
- Register local-storage-get/set/remove as primitives
- Arrows 3x bigger

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 00:04:32 +00:00
a759f4da3b Add Freeze/Thaw page under CEK Machine with live demo
Some checks failed
Build and Deploy / build-and-deploy (push) Has been cancelled
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>
2026-03-14 22:31:34 +00:00
93e140280b Add reactive render stepper to home page, fix nil→NIL in platform JS
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 3m13s
Home page stepper: reactive code view with syntax colouring where
tokens highlight as you step through DOM construction. Each token
is a span with signal-driven classes — current step bold+violet,
completed steps dimmed, upcoming normal. CSSX styling via ~cssx/tw
spreads. Lake preserves imperative DOM across reactive re-renders.

Also fixes: bare lowercase 'nil' in platform_js.py eventDetail and
domGetData — should be NIL (the SX sentinel object).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 20:40:24 +00:00
623f947b52 Fix duplicate sx-cssx-live style tags
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 21s
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>
2026-03-14 20:08:36 +00:00
ae1ba46b44 Add live CEK stepper island — interactive stepping debugger
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 33s
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>
2026-03-14 16:02:41 +00:00
d0a5ce1070 Remove invoke from platform interfaces, add cek-call integration tests
- platform_js.py: remove invoke function definition and PRIMITIVES
  registration, switch domListen handler wrapping to cek-call
- platform_py.py: remove invoke function definition
- run_signal_tests.py: remove invoke patch, use cek_call in batch wrapper
- run_cek_reactive_tests.py: remove invoke, fix primitive lookup to use
  two-level is_primitive/get_primitive, increase recursion limit for
  interpreted CEK evaluation
- test-cek-reactive.sx: add 7 new tests covering cek-call dispatch with
  computed, effect, cleanup, batch coalescing

All 79 tests pass (20 signal + 43 CEK + 16 CEK reactive).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 10:29:32 +00:00
455e48df07 Replace invoke with cek-call in reactive island primitives
All signal operations (computed, effect, batch, etc.) now dispatch
function calls through cek-call, which routes SX lambdas via cek-run
and native callables via apply. This replaces the invoke shim.

Key changes:
- cek.sx: add cek-call (defined before reactive-shift-deref), replace
  invoke in subscriber disposal and ReactiveResetFrame handler
- signals.sx: replace all 11 invoke calls with cek-call
- js.sx: fix octal escape in js-quote-string (char-from-code 0)
- platform_js.py: fix JS append to match Python (list concat semantics),
  add Continuation type guard in PLATFORM_CEK_JS, add scheduleIdle
  safety check, module ordering (cek before signals)
- platform_py.py: fix ident-char regex (remove [ ] from valid chars),
  module ordering (cek before signals)
- run_js_sx.py: emit PLATFORM_CEK_JS before transpiled spec files
- page-functions.sx: add cek and provide page functions for SX URLs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 10:11:48 +00:00
f96506024e Add CEK Machine section under Geography with live island demos
geography/cek.sx: overview page (three registers, deref-as-shift
explanation) + demo page with 5 live islands (counter, computed chain,
reactive attrs, stopwatch effect+cleanup, batch coalescing). Nav entry,
router routes, defpage definitions. CEK exports (cekRun, makeCekState,
makeReactiveResetFrame, evalExpr) added to Sx public API via
platform_js.py.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 01:37:16 +00:00
90febbd91e Bootstrap CEK as default evaluator on both JS and Python sides
SPEC_MODULES + SPEC_MODULE_ORDER for frames/cek in platform_js.py,
PLATFORM_CEK_JS + CEK_FIXUPS_JS constants, auto-inclusion in
run_js_sx.py, 70+ RENAMES in js.sx. Python: CEK always-include in
bootstrap_py.py, eval_expr/trampoline overridden to cek_run in
platform_py.py with _tree_walk_* preserved for test runners.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 01:13:11 +00:00
f3a9f3ccc0 Collapse signal platform primitives into pure SX dicts
Replace _Signal class (Python) and SxSignal constructor (JS) with plain
dicts keyed by "__signal". Nine platform accessor functions become ~20
lines of pure SX in signals.sx. type-of returns "dict" for signals;
signal? is now a structural predicate (dict? + has-key?).

Net: -168 lines platform, +120 lines SX. Zero platform primitives for
reactivity — signals compile to any host via the bootstrappers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 00:04:38 +00:00
dcc73a68d5 Collapse reactive islands into scopes: replace TrackingContext and *island-scope* with scope-push!/scope-pop!/context
Reactive tracking (deref/computed/effect dep discovery) and island lifecycle
now use the general scoped effects system instead of parallel infrastructure.
Two scope names: "sx-reactive" for tracking context, "sx-island-scope" for
island disposable collection. Eliminates ~98 net lines: _TrackingContext class,
7 tracking context platform functions (Python + JS), *island-scope* global,
and corresponding RENAME_MAP entries. All 20 signal tests pass (17 original +
3 new scope integration tests), plus CEK/continuation/type tests clean.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 23:09:09 +00:00
11fdd1a840 Unify scoped effects: scope as general primitive, provide as sugar
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 12m54s
- 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>
2026-03-13 17:30:34 +00:00
2de4ba8c57 Refactor spread to use provide/emit! internally
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>
2026-03-13 15:41:32 +00:00
214963ea6a Unicode escapes, variadic infix fix, spreads demos, scoped-effects + foundations plans
- Add \uXXXX unicode escape support to parser.py and parser.sx spec
- Add char-from-code primitive (Python chr(), JS String.fromCharCode())
- Fix variadic infix operators in both bootstrappers (js.sx, py.sx) —
  (+ a b c d) was silently dropping terms, now left-folds correctly
- Rebootstrap sx_ref.py and sx-browser.js with all fixes
- Fix 3 pre-existing map-dict test failures in shared/sx/tests/run.py
- Add live demos alongside examples in spreads essay (side-by-side layout)
- Add scoped-effects plan: algebraic effects as unified foundation for
  spread/collect/island/lake/signal/context
- Add foundations plan: CEK machine, the computational floor, three-axis
  model (depth/topology/linearity), Curry-Howard correspondence
- Route both plans in page-functions.sx and nav-data.sx

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 12:03:58 +00:00
f52b9e880b Guard all appendChild calls against spread values
The previous fix only guarded domAppend/domInsertAfter, but many
platform JS functions (asyncRenderChildren, asyncRenderElement,
asyncRenderMap, render, sxRenderWithEnv) call appendChild directly.

Add _spread guards to all direct appendChild sites. For async element
rendering, merge spread attrs onto parent (class/style join, others
overwrite) matching the sync adapter behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 03:41:07 +00:00
9284a946ba Guard domAppend/domInsertAfter against spread values
Spread values (from ~cssx/tw etc.) are attribute dicts, not DOM nodes.
When they appear in non-element contexts (fragments, islands, lakes,
reactive branches), they must not be passed to appendChild/insertBefore.

Add _spread guard to platform domAppend and domInsertAfter — fixes
TypeError: Node.appendChild: Argument 1 does not implement interface Node.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 03:35:00 +00:00
ea2b71cfa3 Add provide/context/emit!/emitted — render-time dynamic scope
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>
2026-03-13 02:58:21 +00:00
41097eeef9 Add spread + collect primitives, rewrite ~cssx/tw as defcomp
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>
2026-03-13 02:38:31 +00:00
5f06e2e2cc Spec URL evaluation in router.sx, bootstrap to Python/JS
Add url-to-expr, auto-quote-unknowns, prepare-url-expr to router.sx —
the canonical URL-to-expression pipeline. Dots→spaces, parse, then
auto-quote unknown symbols as strings (slugs). The same spec serves
both server (Python) and client (JS) route handling.

- router.sx: three new pure functions for URL evaluation
- bootstrap_py.py: auto-include router module with html adapter
- platform_js.py: export urlToExpr/autoQuoteUnknowns/prepareUrlExpr
- sx_router.py: replace hand-written auto_quote_slugs with bootstrapped
  prepare_url_expr — delete ~50 lines of hardcoded function name sets
- Rebootstrap sx_ref.py (4331 lines) and sx-browser.js

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 23:05:01 +00:00
8f88e52b27 Add DOM primitives (dom-set-prop, dom-call-method, dom-post-message), bump SW cache v2, remove video demo
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 6m57s
New platform_js primitives for direct DOM property/method access and
cross-origin iframe communication. Service worker static cache bumped
to v2 to flush stale assets. Removed experimental video embed from
header island, routes, and home page.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 21:51:05 +00:00
95ffc0ecb7 Merge worktree-typed into macros: defcomp type annotations 2026-03-11 21:02:12 +00:00
4d54be6b6b Restructure SX docs nav into 4 top-level sections with nested routing
New hierarchy: Geography (Reactive Islands, Hypermedia Lakes, Marshes,
Isomorphism), Language (Docs, Specs, Bootstrappers, Testing),
Applications (CSSX, Protocols), Etc (Essays, Philosophy, Plans).

All routes updated to match: /reactive/* → /geography/reactive/*,
/docs/* → /language/docs/*, /essays/* → /etc/essays/*, etc.
Updates nav-data.sx, all defpage routes, API endpoints, internal links
across 43 files. Enhanced find-nav-match for nested group resolution.

Also includes: page-helpers-demo sf-total fix (reduce instead of set!),
rebootstrapped sx-browser.js and sx_ref.py, defensive slice/rest guards.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 18:50:31 +00:00
ff6c1fab71 Fix process-bindings scope loss and async-invoke arity, bootstrap async adapter
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>
2026-03-11 16:38:47 +00:00
c95e19dcf2 Page helpers demo: defisland, map-in-children fix, _eval_slot ref evaluator
- Add page-helpers-demo page with defisland ~demo-client-runner (pure SX,
  zero JS files) showing spec functions running on both server and client
- Fix _aser_component children serialization: flatten list results from map
  instead of serialize(list) which wraps in parens creating ((div ...) ...)
  that re-parses as invalid function call. Fixed in adapter-async.sx spec
  and async_eval_ref.py
- Switch _eval_slot to use async_eval_ref.py when SX_USE_REF=1 (was
  hardcoded to async_eval.py)
- Add Island type support to async_eval_ref.py: import, SSR rendering,
  aser dispatch, thread-first, defisland in _ASER_FORMS
- Add server affinity check: components with :affinity :server expand
  even when _expand_components is False
- Add diagnostic _aser_stack context to EvalError messages
- New spec files: adapter-async.sx, page-helpers.sx, platform_js.py
- Bootstrappers: page-helpers module support, performance.now() timing
- 0-arity lambda event handler fix in adapter-dom.sx

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 14:30:12 +00:00