;; ---------------------------------------------------------------------------
;; Isolated Evaluator — Shared platform layer, isolated JS, Rust WASM
;; ---------------------------------------------------------------------------

(defcomp ()
  (~docs/page :title "Isolated Evaluator"

    (~docs/section :title "Context" :id "context"
      (p "The SX spec is already split into three layers:")
      (ul (~tw :tokens "list-disc list-inside space-y-1 mt-2")
        (li (code "spec/") " \u2014 Core language (19 files): evaluator, parser, primitives, CEK, types, continuations. Host-independent.")
        (li (code "web/") " \u2014 Web framework (20 files): signals, adapters, engine, orchestration, boot, router, deps. Built on core spec.")
        (li (code "sx/") " \u2014 Application (sx-docs website). Built on web framework."))
      (p "Bootstrappers search " (code "spec/ \u2192 web/ \u2192 shared/sx/ref/") " for " (code ".sx") " files. The separation is clean.")
      (p "This plan takes the next step: " (strong "isolate the evaluator from the real world") ". The JS evaluator should run in the same sandbox as Rust/WASM \u2014 unable to touch DOM, fetch, timers, or storage directly. Both evaluators call into a shared " (code "sx-platform.js") " for all browser access.")
      (p "This also involves sorting out the JavaScript: eliminating hand-coded JS that duplicates specced " (code ".sx") " logic, and moving web framework " (code ".sx") " from compiled-into-evaluator to runtime-evaluated."))

    (~docs/section :title "Existing Architecture" :id "existing"
      (h4 (~tw :tokens "font-semibold mt-4 mb-2") "Three-layer spec split (DONE)")
      (div (~tw :tokens "overflow-x-auto rounded border border-stone-200 mb-4")
        (table (~tw :tokens "w-full text-left text-sm")
          (thead (tr (~tw :tokens "border-b border-stone-200 bg-stone-100")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Layer")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Directory")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Files")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Content")))
          (tbody
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Core spec")
              (td (~tw :tokens "px-3 py-2 text-stone-700") (code "spec/"))
              (td (~tw :tokens "px-3 py-2 text-stone-700") "19")
              (td (~tw :tokens "px-3 py-2 text-stone-600") "eval, parser, primitives, render, types, CEK, continuations, boundary-core"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Web framework")
              (td (~tw :tokens "px-3 py-2 text-stone-700") (code "web/"))
              (td (~tw :tokens "px-3 py-2 text-stone-700") "20")
              (td (~tw :tokens "px-3 py-2 text-stone-600") "adapters, signals, engine, orchestration, boot, router, deps, forms, boundary-web"))
            (tr
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Application")
              (td (~tw :tokens "px-3 py-2 text-stone-700") (code "sx/"))
              (td (~tw :tokens "px-3 py-2 text-stone-700") "\u2014")
              (td (~tw :tokens "px-3 py-2 text-stone-600") "sx-docs website, page components, content")))))

      (h4 (~tw :tokens "font-semibold mt-4 mb-2") "Rust/WASM evaluator (DONE)")
      (p (code "sx-rust/") " has a working parser + evaluator + render-to-html in WASM: 9,823 lines generated Rust, 75 real primitives, 154 stubs, 92 tests passing. Currently pure computation \u2014 no DOM interaction.")

      (h4 (~tw :tokens "font-semibold mt-4 mb-2") "What needs to change")
      (p "Currently " (strong "everything") " (core + web framework) gets compiled into one monolithic " (code "sx-browser.js") ". The web framework " (code ".sx") " files (signals, engine, orchestration, boot, etc.) are baked into the evaluator output by the bootstrapper. They should instead be " (strong "evaluated at runtime") " by the core evaluator, like any other " (code ".sx") " code.")
      (p "The JavaScript platform primitives (DOM, fetch, timers, storage) are also inlined into the bootstrapped output. They need to be extracted into a standalone " (code "sx-platform.js") " module that both JS and WASM evaluators share."))


    ;; -----------------------------------------------------------------------
    ;; What's core vs web (bootstrapped vs runtime)
    ;; -----------------------------------------------------------------------

    (~docs/section :title "Bootstrapped vs Runtime-Evaluated" :id "bootstrap-vs-runtime"
      (p "The key question: what MUST be compiled into the evaluator vs what can be loaded as " (code ".sx") " at runtime?")

      (h4 (~tw :tokens "font-semibold mt-4 mb-2") "Must be bootstrapped (core spec)")
      (div (~tw :tokens "overflow-x-auto rounded border border-stone-200 mb-4")
        (table (~tw :tokens "w-full text-left text-sm")
          (thead (tr (~tw :tokens "border-b border-stone-200 bg-stone-100")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "File")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Dir")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Why")))
          (tbody
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") (code "eval.sx"))
              (td (~tw :tokens "px-3 py-2 text-stone-700") "spec/")
              (td (~tw :tokens "px-3 py-2 text-stone-600") "IS the language \u2014 can't evaluate without it"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") (code "parser.sx"))
              (td (~tw :tokens "px-3 py-2 text-stone-700") "spec/")
              (td (~tw :tokens "px-3 py-2 text-stone-600") "Can't read .sx source without a parser"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") (code "primitives.sx"))
              (td (~tw :tokens "px-3 py-2 text-stone-700") "spec/")
              (td (~tw :tokens "px-3 py-2 text-stone-600") "80+ built-in pure functions \u2014 must be native"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") (code "render.sx"))
              (td (~tw :tokens "px-3 py-2 text-stone-700") "spec/")
              (td (~tw :tokens "px-3 py-2 text-stone-600") "HTML_TAGS registry, parse-element-args"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") (code "adapter-html.sx"))
              (td (~tw :tokens "px-3 py-2 text-stone-700") "web/")
              (td (~tw :tokens "px-3 py-2 text-stone-600") "render-to-html \u2014 co-recursive with eval-expr"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") (code "adapter-sx.sx"))
              (td (~tw :tokens "px-3 py-2 text-stone-700") "web/")
              (td (~tw :tokens "px-3 py-2 text-stone-600") "aser (wire format) \u2014 co-recursive with eval-expr"))
            (tr
              (td (~tw :tokens "px-3 py-2 text-stone-700") (code "adapter-dom.sx"))
              (td (~tw :tokens "px-3 py-2 text-stone-700") "web/")
              (td (~tw :tokens "px-3 py-2 text-stone-600") "render-to-dom \u2014 co-recursive with eval-expr")))))

      (h4 (~tw :tokens "font-semibold mt-4 mb-2") "Runtime-evaluated (web framework)")
      (div (~tw :tokens "overflow-x-auto rounded border border-stone-200 mb-4")
        (table (~tw :tokens "w-full text-left text-sm")
          (thead (tr (~tw :tokens "border-b border-stone-200 bg-stone-100")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "File")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Dir")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Why it can be runtime")))
          (tbody
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") (code "signals.sx"))
              (td (~tw :tokens "px-3 py-2 text-stone-700") "web/")
              (td (~tw :tokens "px-3 py-2 text-stone-600") "Pure computation \u2014 dicts with markers, no new types"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") (code "engine.sx"))
              (td (~tw :tokens "px-3 py-2 text-stone-700") "web/")
              (td (~tw :tokens "px-3 py-2 text-stone-600") "Pure logic \u2014 trigger parsing, swap specs, morph"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") (code "orchestration.sx"))
              (td (~tw :tokens "px-3 py-2 text-stone-700") "web/")
              (td (~tw :tokens "px-3 py-2 text-stone-600") "Event binding + fetch \u2014 calls platform primitives"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") (code "boot.sx"))
              (td (~tw :tokens "px-3 py-2 text-stone-700") "web/")
              (td (~tw :tokens "px-3 py-2 text-stone-600") "Page lifecycle \u2014 calls platform primitives"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") (code "router.sx"))
              (td (~tw :tokens "px-3 py-2 text-stone-700") "web/")
              (td (~tw :tokens "px-3 py-2 text-stone-600") "URL pattern matching \u2014 pure computation"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") (code "deps.sx"))
              (td (~tw :tokens "px-3 py-2 text-stone-700") "web/")
              (td (~tw :tokens "px-3 py-2 text-stone-600") "Component dependency analysis \u2014 pure AST walking"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") (code "page-helpers.sx"))
              (td (~tw :tokens "px-3 py-2 text-stone-700") "web/")
              (td (~tw :tokens "px-3 py-2 text-stone-600") "Data transformation helpers"))
            (tr
              (td (~tw :tokens "px-3 py-2 text-stone-700") (code "forms.sx"))
              (td (~tw :tokens "px-3 py-2 text-stone-700") "web/")
              (td (~tw :tokens "px-3 py-2 text-stone-600") "Server-only definition forms")))))

      (h4 (~tw :tokens "font-semibold mt-4 mb-2") "adapter-dom.sx reactive split")
      (p (code "adapter-dom.sx") " contains reactive-aware code (" (code "reactive-text") ", " (code "reactive-attr") ", " (code "render-dom-island") ", " (code "render-dom-lake") ") interleaved with core DOM rendering. These call " (code "signal?") " and " (code "deref") " from " (code "signals.sx") " via environment lookup \u2014 no compile-time dependency. Option: split reactive DOM functions into " (code "adapter-dom-reactive.sx") " (web/ layer), keeping base " (code "adapter-dom.sx") " purely about elements/text/fragments/components.")

      (h4 (~tw :tokens "font-semibold mt-4 mb-2") "Hand-coded JS to clean up")
      (ul (~tw :tokens "list-disc list-inside space-y-2 mt-2")
        (li (code "CONTINUATIONS_JS") " in " (code "platform_js.py") " \u2014 hand-coded shift/reset. Should use specced " (code "continuations.sx") " or be eliminated if continuations are application-level.")
        (li (code "ASYNC_IO_JS") " in " (code "platform_js.py") " \u2014 hand-coded async rendering dispatch. Already replaced by " (code "adapter-async.sx") " for Python. JS version should also be bootstrapped or eliminated.")
        (li "Various wrapper functions in " (code "PLATFORM_BOOT_JS") " that duplicate logic from " (code "boot.sx") ".")))


    ;; -----------------------------------------------------------------------
    ;; Phase 1: Extract sx-platform.js
    ;; -----------------------------------------------------------------------

    (~docs/section :title "Phase 1: Extract sx-platform.js" :id "phase-1"
      (p (strong "Goal:") " All real-world-touching JavaScript lives in one standalone module. The evaluator never directly accesses " (code "document") ", " (code "window") ", " (code "fetch") ", " (code "localStorage") ", " (code "history") ", etc.")

      (h4 (~tw :tokens "font-semibold mt-4 mb-2") "Architecture")
      (~docs/code :src (highlight "                    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n                    \u2502  sx-platform.js  \u2502  \u2190 DOM, fetch, timers, storage\n                    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                             \u2502\n              \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n              \u2502                             \u2502\n    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510         \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n    \u2502  sx-evaluator.js   \u2502         \u2502 sx-wasm-shim.js \u2502\n    \u2502  (isolated JS)     \u2502         \u2502 (WASM instance  \u2502\n    \u2502                    \u2502         \u2502  + handle table) \u2502\n    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518         \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518" "text"))

      (h4 (~tw :tokens "font-semibold mt-4 mb-2") "What moves into sx-platform.js")
      (p "Extracted from " (code "platform_js.py") " string constants:")
      (div (~tw :tokens "overflow-x-auto rounded border border-stone-200 mb-4")
        (table (~tw :tokens "w-full text-left text-sm")
          (thead (tr (~tw :tokens "border-b border-stone-200 bg-stone-100")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Category")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Source")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "~Functions")))
          (tbody
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "DOM primitives")
              (td (~tw :tokens "px-3 py-2 text-stone-700") (code "PLATFORM_DOM_JS"))
              (td (~tw :tokens "px-3 py-2 text-stone-600") "~50 (createElement, setAttribute, appendChild...)"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Engine platform")
              (td (~tw :tokens "px-3 py-2 text-stone-700") (code "PLATFORM_ENGINE_PURE_JS"))
              (td (~tw :tokens "px-3 py-2 text-stone-600") "~6 (locationHref, pushState, nowMs...)"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Orchestration platform")
              (td (~tw :tokens "px-3 py-2 text-stone-700") (code "PLATFORM_ORCHESTRATION_JS"))
              (td (~tw :tokens "px-3 py-2 text-stone-600") "~80 (fetch, abort, timers, SSE, scroll, media...)"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Boot platform")
              (td (~tw :tokens "px-3 py-2 text-stone-700") (code "PLATFORM_BOOT_JS"))
              (td (~tw :tokens "px-3 py-2 text-stone-600") "~20 (mount target, localStorage, cookies, logging...)"))
            (tr
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Parser helpers")
              (td (~tw :tokens "px-3 py-2 text-stone-700") (code "PLATFORM_PARSER_JS"))
              (td (~tw :tokens "px-3 py-2 text-stone-600") "~4 (isIdentStart, parseNumber...)")))))

      (h4 (~tw :tokens "font-semibold mt-4 mb-2") "Isolation rule")
      (p "After extraction, searching " (code "sx-evaluator.js") " for " (code "document") ", " (code "window") ", " (code "fetch") ", " (code "localStorage") ", " (code "history") ", " (code "setTimeout") ", " (code "console") " should find " (strong "zero") " direct references.")

      (h4 (~tw :tokens "font-semibold mt-4 mb-2") "The callSxFunction bridge")
      (p "Platform code (event listeners, timers) needs to invoke SX lambdas. The evaluator provides a single " (code "callSxFunction(fn, args) \u2192 result") " bridge to the platform at registration time. This is the ONE evaluator-to-platform callback.")

      (h4 (~tw :tokens "font-semibold mt-4 mb-2") "Implementation")
      (ul (~tw :tokens "list-disc list-inside space-y-2 mt-2")
        (li "Modify " (code "platform_js.py") " to emit platform functions as a separate output section")
        (li "Create " (code "sx-platform.js") " as an IIFE that sets " (code "globalThis.SxPlatform = {...}"))
        (li "The evaluator IIFE reads " (code "globalThis.SxPlatform") " at init, registers each function as a PRIMITIVE")
        (li "Clean up " (code "CONTINUATIONS_JS") " and " (code "ASYNC_IO_JS") " \u2014 eliminate or bootstrap")
        (li "Test that existing pages work identically")))


    ;; -----------------------------------------------------------------------
    ;; Phase 2: Isolate the JS Evaluator
    ;; -----------------------------------------------------------------------

    (~docs/section :title "Phase 2: Isolate the JS Evaluator" :id "phase-2"
      (p (strong "Goal:") " " (code "sx-evaluator.js") " contains ONLY core spec + render adapters. Web framework " (code ".sx") " is evaluated at runtime.")

      (h4 (~tw :tokens "font-semibold mt-4 mb-2") "Core-only build")
      (p "The bootstrapper already supports selecting which modules to compile. A core-only build:")
      (~docs/code :src (highlight "# In run_js_sx.py \u2014 core-only build\ncompile_ref_to_js(\n    adapters=[\"parser\", \"html\", \"sx\", \"dom\"],  # core spec + adapters\n    modules=None,       # no signals, engine, orchestration, boot\n    extensions=None,    # no continuations\n    spec_modules=None   # no deps, router, cek, frames, page-helpers\n)" "python"))

      (h4 (~tw :tokens "font-semibold mt-4 mb-2") "Web framework loading")
      (p "Web framework " (code ".sx") " files ship as " (code "<script type=\"text/sx-lib\">") " blocks. The platform boot shim evaluates them before component scripts:")
      (~docs/code :src (highlight "<script src=\"/static/scripts/sx-platform.js\"></script>\n<script src=\"/static/scripts/sx-evaluator.js\"></script>\n<script type=\"text/sx-lib\">\n  ;; concatenated web/ framework: signals, deps, router,\n  ;; engine, orchestration, boot\n</script>\n<script type=\"text/sx\" data-components>\n  ;; page component definitions\n</script>" "html"))

      (h4 (~tw :tokens "font-semibold mt-4 mb-2") "Boot chicken-and-egg")
      (p (code "boot.sx") " orchestrates the boot sequence but is itself web framework code. Solution: thin native boot shim (~30 lines) in " (code "sx-platform.js") ":")
      (~docs/code :src (highlight "SxPlatform.boot = function(evaluator) {\n  // 1. Evaluate web framework .sx libraries\n  var libs = document.querySelectorAll('script[type=\"text/sx-lib\"]');\n  for (var i = 0; i < libs.length; i++) {\n    evaluator.evalSource(libs[i].textContent);\n  }\n  // 2. Call boot-init (defined in boot.sx)\n  evaluator.callFunction('boot-init');\n};" "javascript"))

      (h4 (~tw :tokens "font-semibold mt-4 mb-2") "Performance")
      (p "Parsing + evaluating ~5,000 lines of web framework " (code ".sx") " at startup takes ~10\u201350ms. After " (code "define") ", functions are Lambda objects dispatched identically to compiled functions. " (strong "Zero ongoing performance difference.")))


    ;; -----------------------------------------------------------------------
    ;; Phase 3: Wire Up Rust/WASM
    ;; -----------------------------------------------------------------------

    (~docs/section :title "Phase 3: Wire Up Rust/WASM" :id "phase-3"
      (p (strong "Goal:") " Rust evaluator calls " (code "sx-platform.js") " via wasm-bindgen imports. Handle table bridges DOM references.")

      (h4 (~tw :tokens "font-semibold mt-4 mb-2") "Handle table (JS-side)")
      (~docs/code :src (highlight "// In sx-wasm-shim.js\nconst handles = [null];  // index 0 = null handle\nfunction allocHandle(obj) { handles.push(obj); return handles.length - 1; }\nfunction getHandle(id) { return handles[id]; }\nfunction freeHandle(id) { handles[id] = null; }" "javascript"))
      (p "DOM nodes are JS objects. The handle table maps " (code "u32") " IDs to JS objects. Rust stores " (code "Value::Handle(u32)") " and passes the " (code "u32") " to imported JS functions.")

      (h4 (~tw :tokens "font-semibold mt-4 mb-2") "Value::Handle in Rust")
      (~docs/code :src (highlight "// In platform.rs\npub enum Value {\n    // ... existing variants ...\n    Handle(u32),  // opaque reference to JS-side object\n}" "rust"))

      (h4 (~tw :tokens "font-semibold mt-4 mb-2") "WASM imports from platform")
      (~docs/code :src (highlight "#[wasm_bindgen(module = \"/sx-platform-wasm.js\")]\nextern \"C\" {\n    fn platform_create_element(tag: &str) -> u32;\n    fn platform_create_text_node(text: &str) -> u32;\n    fn platform_set_attr(handle: u32, name: &str, value: &str);\n    fn platform_append_child(parent: u32, child: u32);\n    fn platform_add_event_listener(handle: u32, event: &str, callback_id: u32);\n    // ... ~50 DOM primitives\n}" "rust"))

      (h4 (~tw :tokens "font-semibold mt-4 mb-2") "Callback table for events")
      (p "When Rust creates an event handler (a Lambda), it stores it in a callback table and gets a " (code "u32") " ID. JS " (code "addEventListener") " wraps it: when the event fires, JS calls into WASM with the callback ID. Rust looks up the Lambda and evaluates it.")

      (h4 (~tw :tokens "font-semibold mt-4 mb-2") "sx-wasm-shim.js")
      (p "Thin glue (~100 lines):")
      (ul (~tw :tokens "list-disc list-inside space-y-1 mt-2")
        (li "Instantiate WASM module")
        (li "Wire handle table")
        (li "Delegate all platform calls to " (code "sx-platform.js"))
        (li "Provide " (code "invoke_callback") " \u2192 Rust for event dispatch")))


    ;; -----------------------------------------------------------------------
    ;; Phase 4: Web Framework Loading
    ;; -----------------------------------------------------------------------

    (~docs/section :title "Phase 4: Web Framework Loading" :id "phase-4"
      (p (strong "Goal:") " Both JS and WASM evaluators load the same web framework " (code ".sx") " files at runtime.")

      (h4 (~tw :tokens "font-semibold mt-4 mb-2") "Boot sequence (identical for both evaluators)")
      (ol (~tw :tokens "list-decimal list-inside space-y-2 mt-2")
        (li "Load " (code "sx-platform.js") " + evaluator (" (code "sx-evaluator.js") " or " (code "sx-wasm-shim.js") ")")
        (li "Platform registers primitives with evaluator")
        (li "Platform boot shim evaluates " (code "<script type=\"text/sx-lib\">") " blocks")
        (li "Dependency order: signals \u2192 deps \u2192 frames \u2192 router \u2192 page-helpers \u2192 engine \u2192 orchestration \u2192 boot")
        (li (code "boot-init") " called \u2014 processes component scripts, hydrates, initializes engine")
        (li "Page is interactive"))

      (h4 (~tw :tokens "font-semibold mt-4 mb-2") "Library dependency order")
      (~docs/code :src (highlight "signals.sx          \u2190 no SX deps (uses only core primitives)\ndeps.sx             \u2190 no SX deps\nframes.sx           \u2190 no SX deps\nrouter.sx           \u2190 no SX deps\npage-helpers.sx     \u2190 no SX deps\nengine.sx           \u2190 uses render.sx (core), adapter-dom.sx (core)\norchestration.sx    \u2190 depends on engine.sx\nboot.sx             \u2190 depends on orchestration.sx" "text")))


    ;; -----------------------------------------------------------------------
    ;; Phase 5: Verification + Rollout
    ;; -----------------------------------------------------------------------

    (~docs/section :title "Phase 5: Verification + Rollout" :id "phase-5"
      (h4 (~tw :tokens "font-semibold mt-4 mb-2") "Shadow comparison")
      (p "Run both JS and WASM evaluators on same input, compare outputs:")
      (ol (~tw :tokens "list-decimal list-inside space-y-1 mt-2")
        (li (strong "Parse") " \u2014 same AST (already testable with current WASM exports)")
        (li (strong "Eval") " \u2014 same values (already testable)")
        (li (strong "Render") " \u2014 same DOM structure (requires Phase 3)"))

      (h4 (~tw :tokens "font-semibold mt-4 mb-2") "Feature flag")
      (p "Server sets " (code "data-sx-runtime=\"wasm\"") " or " (code "\"js\"") " on root element. Boot shim loads appropriate evaluator. Progressive enhancement: try WASM, fall back to JS.")

      (h4 (~tw :tokens "font-semibold mt-4 mb-2") "Test matrix")
      (p "All " (code "test-*.sx") " files from both " (code "spec/") " and " (code "web/") " run on BOTH evaluators."))


    ;; -----------------------------------------------------------------------
    ;; Principles
    ;; -----------------------------------------------------------------------

    (~docs/section :title "Principles" :id "principles"
      (ul (~tw :tokens "list-disc list-inside space-y-2")
        (li (strong "Core is what defines the language.") " Parser, evaluator, primitives, render modes. If you can't run SX without it, it's core (" (code "spec/") "). If you can write it " (em "in") " SX, it's web framework (" (code "web/") ").")
        (li (strong "Web framework runs ON the evaluator.") " Signals, engine, orchestration, boot, router, deps \u2014 these are SX programs. They're evaluated at runtime, not compiled into the evaluator.")
        (li (strong "Isolation is the boundary.") " The evaluator can't touch the real world. Platform primitives are the only bridge. JS and WASM evaluators have identical isolation.")
        (li (strong "Shared platform, not duplicated.") " One implementation of every browser primitive in " (code "sx-platform.js") ". Both evaluators use it. Fix a bug once, both get the fix.")
        (li (strong "Handle table is the WASM boundary.") " Rust holds " (code "u32") " IDs. JavaScript holds real objects. Swap the handle table for a different host and the Rust code doesn't change.")
        (li (strong "Progressive, not all-or-nothing.") " WASM is an enhancement. JS remains the fallback. Feature-flagged per page. Gradual and reversible.")))


    ;; -----------------------------------------------------------------------
    ;; Interactions
    ;; -----------------------------------------------------------------------

    (~docs/section :title "Interaction with Other Plans" :id "interactions"
      (ul (~tw :tokens "list-disc list-inside space-y-2")
        (li (strong (a :href "/sx/(etc.(plan.rust-wasm-host))" "Rust/WASM Host")) " \u2014 this plan supersedes it. That plan didn't distinguish core from web framework or propose evaluator isolation. The shared platform layer is the key architectural difference.")
        (li (strong (a :href "/sx/(etc.(plan.wasm-bytecode-vm))" "WASM Bytecode VM")) " \u2014 complementary. This plan bootstraps the tree-walking evaluator. A future bytecode VM compiles SX to bytecodes. The platform layer and handle table are shared.")
        (li (strong (a :href "/sx/(etc.(plan.runtime-slicing))" "Runtime Slicing")) " \u2014 simplified. With web framework as runtime-evaluated " (code ".sx") ", slicing becomes: ship core + only the framework files you need. L0 pages skip signals/engine entirely.")
        (li (strong (a :href "/sx/(etc.(plan.reactive-runtime))" "Reactive Runtime")) " \u2014 signals are web framework code, confirming they layer on top of core without special treatment.")
        (li (strong (a :href "/sx/(etc.(plan.foundations))" "Foundations")) " \u2014 the core/web split is the same principle: small kernel, everything else built on top.")))


    ;; -----------------------------------------------------------------------
    ;; Outcome
    ;; -----------------------------------------------------------------------

    (~docs/section :title "Outcome" :id "outcome"
      (p "After completion:")
      (ul (~tw :tokens "list-disc list-inside space-y-2 mt-2")
        (li "Core evaluator is ~3,200 lines of bootstrapped spec (" (code "spec/") " + adapters from " (code "web/") ").")
        (li "JS evaluator is isolated \u2014 can't touch the real world, same sandbox as WASM.")
        (li "Shared " (code "sx-platform.js") " provides all browser primitives to both evaluators.")
        (li "Rust/WASM evaluator runs in the browser with full DOM rendering via handle table.")
        (li "Web framework " (code ".sx") " files (signals, engine, orchestration, boot) are runtime-evaluated by whichever evaluator is active.")
        (li "Hand-coded JS (" (code "CONTINUATIONS_JS") ", " (code "ASYNC_IO_JS") ") eliminated or bootstrapped from spec.")
        (li "The architecture proof is complete: one spec, isolated evaluator, shared platform, deployment-time target selection.")))))
