Spec layer (orchestration.sx):
- try-client-route now handles :data pages instead of falling back to server
- New abstract primitive resolve-page-data(name, params, callback) — platform
decides transport (HTTP, IPC, cache, etc)
- Extracted swap-rendered-content and resolve-route-target helpers
Platform layer (bootstrap_js.py):
- resolvePageData() browser implementation: fetches /sx/data/<name>, parses
SX response, calls callback. Other hosts provide their own transport.
Server layer (pages.py):
- evaluate_page_data() evaluates :data expr, serializes result as SX
- auto_mount_page_data() mounts /sx/data/ endpoint with per-page auth
- _build_pages_sx now computes component deps for all pages (not just pure)
Test page at /isomorphism/data-test exercises the full pipeline.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove strict deps check — for case expressions like essay pages,
deps includes ALL branches but only one is taken. Instead, just
try to eval the content. If a component is missing, tryEvalContent
catches the error and we transparently fall back to server fetch.
deps field remains in registry for future prefetching use.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Each page entry now includes a deps list of component names needed.
Client checks all deps are loaded before attempting eval — if any
are missing, falls through to server fetch with a clear log message.
No bundle bloat: server sends components for the current page only.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
NIL is a frozen sentinel object ({_nil:true}) which is truthy in JS.
(not expr) compiled to !expr, so (not nil) returned false instead of
true. Fixed to compile as !isSxTruthy(expr) which correctly handles
NIL. This was preventing client-side routing from activating.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SES lockdown may suppress console.error. Use logInfo for error
reporting since we know it works ([sx-ref] prefix visible).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Log "sx:route server fetch <url>" when falling back to network
- Use console.error for eval errors (not console.warn)
- Restructure bind-event to separate client route check from &&-chain
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Shows "pages: N routes loaded" at startup and
"sx:route no match (N routes) /path" when no route matches,
so we can see if routes loaded and why matching fails.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
tryClientRoute now logs why it falls through: has-data, no content,
eval failed, or #main-panel not found. tryEvalContent logs the actual
error on catch. Added logWarn platform function (console.warn).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
bind-event now checks tryClientRoute before executeRequest for GET
clicks on links. Previously only boost links (inside [sx-boost]
containers) attempted client routing — explicit sx-get links like
~nav-link always hit the network. Now essay/doc nav links render
client-side when possible.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two fixes for sx-browser.js (spec-compiled) vs sx.js (hand-written):
1. CSS meta tag mismatch: initCssTracking read meta[name="sx-css-hash"]
but the page template uses meta[name="sx-css-classes"]. This left
_cssHash empty, causing the server to send ALL CSS as "new" on every
navigation, appending duplicate rules that broke Tailwind responsive
ordering (e.g. menu bar layout).
2. Stale verb info after morph: execute-request used captured verbInfo
from bind time. After morph updated element attributes (e.g. during
OOB nav swap), click handlers still fired with old URLs. Now re-reads
verb info from the element first, matching sx.js behavior.
Also includes: render-expression dispatch in eval.sx, NIL guard for
preload cache in bootstrap_js.py, and helpers.py switched to
sx-browser.js.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
engine.sx now contains only pure logic: parsing, morph, swap, headers,
retry, target resolution, etc. orchestration.sx contains the browser
wiring: request execution, trigger binding, SSE, boost, post-swap
lifecycle, and init. Dependency is one-way: orchestration → engine.
Bootstrap compiler gains "orchestration" as a separate adapter with
deps on engine+dom. Engine-only builds get morph/swap without the
full browser runtime.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>