Add CEK reactive tests (9/9), fix test runners for CEK-default mode
test-cek-reactive.sx: 9 tests across 4 suites — deref pass-through, signal without reactive-reset, reactive-reset shift with continuation capture, scope disposal cleanup. run_cek_reactive_tests.py: new runner loading signals+frames+cek. Both test runners override sx_ref.eval_expr back to tree-walk so interpreted .sx uses tree-walk internally. Plan page added to sx-docs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -226,7 +226,9 @@
|
||||
(dict :label "Scoped Effects" :href "/sx/(etc.(plan.scoped-effects))"
|
||||
:summary "Algebraic effects as the unified foundation — spreads, islands, lakes, signals, and context are all instances of one primitive: a named scope with downward value, upward accumulation, and a propagation mode.")
|
||||
(dict :label "Foundations" :href "/sx/(etc.(plan.foundations))"
|
||||
:summary "The computational floor — from scoped effects through algebraic effects and delimited continuations to the CEK machine. Why three registers are irreducible, and the three-axis model (depth, topology, linearity).")))
|
||||
:summary "The computational floor — from scoped effects through algebraic effects and delimited continuations to the CEK machine. Why three registers are irreducible, and the three-axis model (depth, topology, linearity).")
|
||||
(dict :label "Deref as Shift" :href "/sx/(etc.(plan.cek-reactive))"
|
||||
:summary "Phase B: replace explicit effect wrapping with implicit continuation capture. Deref inside reactive-reset performs shift, capturing the rest of the expression as the subscriber.")))
|
||||
|
||||
(define reactive-islands-nav-items (list
|
||||
(dict :label "Overview" :href "/sx/(geography.(reactive))"
|
||||
|
||||
302
sx/sx/plans/cek-reactive.sx
Normal file
302
sx/sx/plans/cek-reactive.sx
Normal file
@@ -0,0 +1,302 @@
|
||||
;; Deref as Shift — CEK-Based Reactive DOM Renderer
|
||||
;; Phase B: replace explicit effects with implicit continuation capture.
|
||||
|
||||
(defcomp ~plans/cek-reactive/plan-cek-reactive-content ()
|
||||
(~docs/page :title "Deref as Shift — CEK-Based Reactive DOM Renderer"
|
||||
|
||||
(p :class "text-stone-500 text-sm italic mb-8"
|
||||
"Phase A collapsed signals to plain dicts with zero platform primitives. "
|
||||
"Phase B replaces explicit effect wrapping in the reactive DOM renderer "
|
||||
"with implicit continuation capture: when " (code "deref") " encounters a signal "
|
||||
"inside a " (code "reactive-reset") " boundary, it performs " (code "shift") ", "
|
||||
"capturing the rest of the expression as a continuation. "
|
||||
"That continuation IS the subscriber.")
|
||||
|
||||
;; =====================================================================
|
||||
;; The Insight
|
||||
;; =====================================================================
|
||||
|
||||
(~docs/section :title "The Insight" :id "insight"
|
||||
|
||||
(p "Each reactive binding is a micro-computation:")
|
||||
(ul :class "list-disc pl-6 mb-4 space-y-1"
|
||||
(li (code "reactive-text") ": given signal value, set text node content to " (code "(str value)"))
|
||||
(li (code "reactive-attr") ": given signal value, set attribute to " (code "(str value)")))
|
||||
|
||||
(p "Currently wrapped in explicit " (code "effect") " calls. With deref-as-shift, "
|
||||
"the continuation captures this automatically:")
|
||||
|
||||
(~docs/code :code (highlight
|
||||
";; User writes:\n(div :class (str \"count-\" (deref counter))\n (str \"Value: \" (deref counter)))\n\n;; Renderer internally wraps each expression:\n(div :class (reactive-reset update-attr-fn (str \"count-\" (deref counter)))\n (reactive-reset update-text-fn (str \"Value: \" (deref counter))))\n\n;; When (deref counter) hits a signal inside reactive-reset:\n;; 1. Shift: capture continuation (str \"count-\" [HOLE])\n;; 2. Register continuation as signal subscriber\n;; 3. Return current value for initial render\n;; When counter changes:\n;; Re-invoke continuation with new value → update-fn updates DOM"
|
||||
"lisp")))
|
||||
|
||||
;; =====================================================================
|
||||
;; Step 1: Bootstrap CEK to JavaScript
|
||||
;; =====================================================================
|
||||
|
||||
(~docs/section :title "Step 1: Bootstrap CEK to JavaScript" :id "step-1"
|
||||
|
||||
(p "Add " (code "frames.sx") " + " (code "cek.sx") " to the JS build pipeline. "
|
||||
"Currently CEK is Python-only.")
|
||||
|
||||
(~docs/subsection :title "1a. platform_js.py — SPEC_MODULES + platform code"
|
||||
|
||||
(p "Add to " (code "SPEC_MODULES") " dict:")
|
||||
(~docs/code :code (highlight
|
||||
"\"frames\": (\"frames.sx\", \"frames (CEK continuation frames)\"),\n\"cek\": (\"cek.sx\", \"cek (explicit CEK machine evaluator)\"),\n\n# Add ordering (new constant):\nSPEC_MODULE_ORDER = [\"deps\", \"frames\", \"page-helpers\", \"router\", \"signals\", \"cek\"]"
|
||||
"python"))
|
||||
|
||||
(p "Add " (code "PLATFORM_CEK_JS") " constant (mirrors " (code "PLATFORM_CEK_PY") "):")
|
||||
(~docs/code :code (highlight
|
||||
"// Primitive aliases used by cek.sx\nvar inc = PRIMITIVES[\"inc\"];\nvar dec = PRIMITIVES[\"dec\"];\nvar zip_pairs = PRIMITIVES[\"zip-pairs\"];\n\nfunction makeCekContinuation(captured, restKont) {\n var c = new Continuation(function(v) { return v !== undefined ? v : NIL; });\n c._cek_data = {\"captured\": captured, \"rest-kont\": restKont};\n return c;\n}\nfunction continuationData(c) {\n return (c && c._cek_data) ? c._cek_data : {};\n}"
|
||||
"javascript"))
|
||||
|
||||
(p "Add " (code "CEK_FIXUPS_JS") " — iterative " (code "cek-run") " override:")
|
||||
(~docs/code :code (highlight
|
||||
"cekRun = function(state) {\n while (!cekTerminal_p(state)) { state = cekStep(state); }\n return cekValue(state);\n};"
|
||||
"javascript")))
|
||||
|
||||
(~docs/subsection :title "1b. run_js_sx.py — Update compile_ref_to_js"
|
||||
(ul :class "list-disc pl-6 mb-4 space-y-1"
|
||||
(li "Auto-add " (code "\"frames\"") " when " (code "\"cek\"") " in spec_mod_set (mirror Python " (code "bootstrap_py.py") ")")
|
||||
(li "Auto-add " (code "\"cek\"") " + " (code "\"frames\"") " when " (code "\"dom\"") " adapter included (CEK needed for reactive rendering)")
|
||||
(li "Use " (code "SPEC_MODULE_ORDER") " for ordering instead of " (code "sorted()"))
|
||||
(li "Add " (code "has_cek") " flag")
|
||||
(li "Include " (code "PLATFORM_CEK_JS") " after transpiled code when " (code "has_cek"))
|
||||
(li "Include " (code "CEK_FIXUPS_JS") " in fixups section when " (code "has_cek"))))
|
||||
|
||||
(~docs/subsection :title "1c. js.sx — RENAMES for predicate functions"
|
||||
(p "Default mangling handles most names. Only add RENAMES where " (code "?")
|
||||
" suffix needs clean JS names:")
|
||||
(~docs/code :code (highlight
|
||||
"\"cek-terminal?\" \"cekTerminalP\"\n\"kont-empty?\" \"kontEmptyP\"\n\"make-cek-continuation\" \"makeCekContinuation\"\n\"continuation-data\" \"continuationData\""
|
||||
"lisp")))
|
||||
|
||||
(~docs/subsection :title "1d. bootstrap_py.py — RENAMES for CEK predicates"
|
||||
(~docs/code :code (highlight
|
||||
"\"cek-terminal?\": \"cek_terminal_p\",\n\"kont-empty?\": \"kont_empty_p\",\n\"make-cek-continuation\": \"make_cek_continuation\",\n\"continuation-data\": \"continuation_data\","
|
||||
"python")))
|
||||
|
||||
(~docs/subsection :title "Verification"
|
||||
(ul :class "list-disc pl-6 mb-4 space-y-1"
|
||||
(li "Rebootstrap JS: " (code "python3 bootstrap_js.py"))
|
||||
(li "Check output contains frame constructors + CEK step functions")
|
||||
(li "Run existing CEK Python tests: " (code "python3 run_cek_tests.py") " (should still pass)"))))
|
||||
|
||||
;; =====================================================================
|
||||
;; Step 2: ReactiveResetFrame + DerefFrame
|
||||
;; =====================================================================
|
||||
|
||||
(~docs/section :title "Step 2: ReactiveResetFrame + DerefFrame" :id "step-2"
|
||||
|
||||
(p "New frame types in " (code "frames.sx") " that enable deref-as-shift.")
|
||||
|
||||
(~docs/subsection :title "2a. New frame constructors"
|
||||
(~docs/code :code (highlight
|
||||
";; ReactiveResetFrame: delimiter for reactive deref-as-shift\n;; Carries an update-fn that gets called with new values on re-render.\n(define make-reactive-reset-frame\n (fn (env update-fn first-render?)\n {:type \"reactive-reset\" :env env :update-fn update-fn\n :first-render first-render?}))\n\n;; DerefFrame: awaiting evaluation of deref's argument\n(define make-deref-frame\n (fn (env)\n {:type \"deref\" :env env}))"
|
||||
"lisp")))
|
||||
|
||||
(~docs/subsection :title "2b. Update kont-capture-to-reset"
|
||||
(p "Must stop at EITHER " (code "\"reset\"") " OR " (code "\"reactive-reset\"") ":")
|
||||
(~docs/code :code (highlight
|
||||
"(define kont-capture-to-reset\n (fn (kont)\n (define scan\n (fn (k captured)\n (if (empty? k)\n (error \"shift without enclosing reset\")\n (let ((frame (first k)))\n (if (or (= (frame-type frame) \"reset\")\n (= (frame-type frame) \"reactive-reset\"))\n (list captured (rest k))\n (scan (rest k) (append captured (list frame))))))))\n (scan kont (list))))"
|
||||
"lisp")))
|
||||
|
||||
(~docs/subsection :title "2c. Helpers to scan for ReactiveResetFrame"
|
||||
(~docs/code :code (highlight
|
||||
"(define has-reactive-reset-frame?\n (fn (kont)\n (if (empty? kont) false\n (if (= (frame-type (first kont)) \"reactive-reset\") true\n (has-reactive-reset-frame? (rest kont))))))\n\n;; Returns 3 values: (captured, frame, rest)\n(define kont-capture-to-reactive-reset\n (fn (kont)\n (define scan\n (fn (k captured)\n (if (empty? k)\n (error \"reactive deref without enclosing reactive-reset\")\n (let ((frame (first k)))\n (if (= (frame-type frame) \"reactive-reset\")\n (list captured frame (rest k))\n (scan (rest k) (append captured (list frame))))))))\n (scan kont (list))))"
|
||||
"lisp"))))
|
||||
|
||||
;; =====================================================================
|
||||
;; Step 3: Make deref a CEK Special Form
|
||||
;; =====================================================================
|
||||
|
||||
(~docs/section :title "Step 3: Make deref a CEK Special Form" :id "step-3"
|
||||
|
||||
(p "When " (code "deref") " encounters a signal inside a " (code "reactive-reset")
|
||||
", perform shift.")
|
||||
|
||||
(~docs/subsection :title "3a. Add to special form dispatch in cek.sx"
|
||||
(p "In the dispatch table (around where " (code "reset") " and " (code "shift") " are):")
|
||||
(~docs/code :code (highlight
|
||||
"(= name \"deref\") (step-sf-deref args env kont)"
|
||||
"lisp")))
|
||||
|
||||
(~docs/subsection :title "3b. step-sf-deref"
|
||||
(p "Evaluates the argument first (push DerefFrame), then decides whether to shift:")
|
||||
(~docs/code :code (highlight
|
||||
"(define step-sf-deref\n (fn (args env kont)\n (make-cek-state\n (first args) env\n (kont-push (make-deref-frame env) kont))))"
|
||||
"lisp")))
|
||||
|
||||
(~docs/subsection :title "3c. Handle DerefFrame in step-continue"
|
||||
(p "When the deref argument is evaluated, decide: shift or return.")
|
||||
(~docs/code :code (highlight
|
||||
"(= ft \"deref\")\n (let ((val value)\n (fenv (get frame \"env\")))\n (if (not (signal? val))\n ;; Not a signal: pass through\n (make-cek-value val fenv rest-k)\n ;; Signal: check for ReactiveResetFrame\n (if (has-reactive-reset-frame? rest-k)\n ;; Perform reactive shift\n (reactive-shift-deref val fenv rest-k)\n ;; No reactive-reset: normal deref (scope-based tracking)\n (do\n (let ((ctx (context \"sx-reactive\" nil)))\n (when ctx\n (let ((dep-list (get ctx \"deps\"))\n (notify-fn (get ctx \"notify\")))\n (when (not (contains? dep-list val))\n (append! dep-list val)\n (signal-add-sub! val notify-fn)))))\n (make-cek-value (signal-value val) fenv rest-k)))))"
|
||||
"lisp")))
|
||||
|
||||
(~docs/subsection :title "3d. reactive-shift-deref — the heart"
|
||||
(~docs/code :code (highlight
|
||||
"(define reactive-shift-deref\n (fn (sig env kont)\n (let ((scan-result (kont-capture-to-reactive-reset kont))\n (captured-frames (first scan-result))\n (reset-frame (nth scan-result 1))\n (remaining-kont (nth scan-result 2))\n (update-fn (get reset-frame \"update-fn\")))\n ;; Sub-scope for nested subscriber cleanup on re-invocation\n (let ((sub-disposers (list)))\n (let ((subscriber\n (fn ()\n ;; Dispose previous nested subscribers\n (for-each (fn (d) (invoke d)) sub-disposers)\n (set! sub-disposers (list))\n ;; Re-invoke: push fresh ReactiveResetFrame (first-render=false)\n (let ((new-reset (make-reactive-reset-frame env update-fn false))\n (new-kont (concat captured-frames\n (list new-reset)\n remaining-kont)))\n (with-island-scope\n (fn (d) (append! sub-disposers d))\n (fn ()\n (cek-run\n (make-cek-value (signal-value sig) env new-kont))))))))\n ;; Register subscriber\n (signal-add-sub! sig subscriber)\n ;; Register cleanup with island scope\n (register-in-scope\n (fn ()\n (signal-remove-sub! sig subscriber)\n (for-each (fn (d) (invoke d)) sub-disposers)))\n ;; Return current value for initial render\n (make-cek-value (signal-value sig) env remaining-kont))))))"
|
||||
"lisp")))
|
||||
|
||||
(~docs/subsection :title "3e. Handle ReactiveResetFrame in step-continue"
|
||||
(p "When expression completes normally (or after re-invocation):")
|
||||
(~docs/code :code (highlight
|
||||
"(= ft \"reactive-reset\")\n (let ((update-fn (get frame \"update-fn\"))\n (first? (get frame \"first-render\")))\n ;; On re-render (not first), call update-fn with new value\n (when (and update-fn (not first?))\n (invoke update-fn value))\n (make-cek-value value env rest-k))"
|
||||
"lisp"))
|
||||
(p (strong "Key:") " On first render, update-fn is NOT called — the value flows back to the caller "
|
||||
"who inserts it into the DOM. On re-render (subscriber fires), update-fn IS called "
|
||||
"to mutate the existing DOM.")))
|
||||
|
||||
;; =====================================================================
|
||||
;; Step 4: Integrate into adapter-dom.sx
|
||||
;; =====================================================================
|
||||
|
||||
(~docs/section :title "Step 4: Integrate into adapter-dom.sx" :id "step-4"
|
||||
|
||||
(p "Add CEK reactive path alongside existing effect-based path, controlled by opt-in flag.")
|
||||
|
||||
(~docs/subsection :title "4a. Opt-in flag"
|
||||
(~docs/code :code (highlight
|
||||
"(define *use-cek-reactive* false)\n(define enable-cek-reactive! (fn () (set! *use-cek-reactive* true)))"
|
||||
"lisp")))
|
||||
|
||||
(~docs/subsection :title "4b. CEK reactive attribute binding"
|
||||
(~docs/code :code (highlight
|
||||
"(define cek-reactive-attr\n (fn (el attr-name expr env)\n (let ((update-fn (fn (val)\n (cond\n (or (nil? val) (= val false)) (dom-remove-attr el attr-name)\n (= val true) (dom-set-attr el attr-name \"\")\n :else (dom-set-attr el attr-name (str val))))))\n ;; Mark for morph protection\n (let ((existing (or (dom-get-attr el \"data-sx-reactive-attrs\") \"\"))\n (updated (if (empty? existing) attr-name (str existing \",\" attr-name))))\n (dom-set-attr el \"data-sx-reactive-attrs\" updated))\n ;; Initial render via CEK with ReactiveResetFrame\n (let ((initial (cek-run\n (make-cek-state expr env\n (list (make-reactive-reset-frame env update-fn true))))))\n (invoke update-fn initial)))))"
|
||||
"lisp")))
|
||||
|
||||
(~docs/subsection :title "4c. Modify render-dom-element dispatch"
|
||||
(p "In attribute processing, add conditional:")
|
||||
(~docs/code :code (highlight
|
||||
"(context \"sx-island-scope\" nil)\n (if *use-cek-reactive*\n (cek-reactive-attr el attr-name attr-expr env)\n (reactive-attr el attr-name\n (fn () (trampoline (eval-expr attr-expr env)))))"
|
||||
"lisp"))
|
||||
(p "Similarly for text positions and conditional rendering."))
|
||||
|
||||
(~docs/subsection :title "4d. CEK reactive text"
|
||||
(~docs/code :code (highlight
|
||||
"(define cek-reactive-text\n (fn (expr env)\n (let ((node (create-text-node \"\"))\n (update-fn (fn (val)\n (dom-set-text-content node (str val)))))\n (let ((initial (cek-run\n (make-cek-state expr env\n (list (make-reactive-reset-frame env update-fn true))))))\n (dom-set-text-content node (str initial))\n node))))"
|
||||
"lisp")))
|
||||
|
||||
(~docs/subsection :title "4e. What stays unchanged"
|
||||
(ul :class "list-disc pl-6 mb-4 space-y-1"
|
||||
(li (code "reactive-list") " — keyed reconciliation is complex; keep effect-based for now")
|
||||
(li (code "reactive-spread") " — spread tracking is complex; keep effect-based")
|
||||
(li (code "effect") ", " (code "computed") " — still needed for non-rendering side effects")
|
||||
(li "Existing " (code "reactive-*") " functions — remain as default path"))))
|
||||
|
||||
;; =====================================================================
|
||||
;; Step 5: Tests
|
||||
;; =====================================================================
|
||||
|
||||
(~docs/section :title "Step 5: Tests" :id "step-5"
|
||||
|
||||
(~docs/subsection :title "5a. test-cek-reactive.sx"
|
||||
(p "Tests:")
|
||||
(ol :class "list-decimal pl-6 mb-4 space-y-1"
|
||||
(li (code "deref") " non-signal passes through (no shift)")
|
||||
(li (code "deref") " signal without reactive-reset: returns value, no subscription")
|
||||
(li (code "deref") " signal with reactive-reset: shifts, registers subscriber, update-fn called on change")
|
||||
(li "Expression with deref: " (code "(str \"hello \" (deref sig))") " — continuation captures rest")
|
||||
(li "Multi-deref: both signals create subscribers, both fire correctly")
|
||||
(li "Disposal: removing island scope unsubscribes all continuations")
|
||||
(li "Stale subscriber cleanup: re-invocation disposes nested subscribers")))
|
||||
|
||||
(~docs/subsection :title "5b. run_cek_reactive_tests.py"
|
||||
(p "Mirrors " (code "run_cek_tests.py") ". "
|
||||
"Loads frames.sx, cek.sx, signals.sx, runs test-cek-reactive.sx.")))
|
||||
|
||||
;; =====================================================================
|
||||
;; Step 6: Browser Demo
|
||||
;; =====================================================================
|
||||
|
||||
(~docs/section :title "Step 6: Browser Demo" :id "step-6"
|
||||
(p "Demo showing:")
|
||||
(ul :class "list-disc pl-6 mb-4 space-y-1"
|
||||
(li "Counter island with implicit reactivity (no explicit effects)")
|
||||
(li (code "(deref counter)") " in text position auto-updates")
|
||||
(li (code "(str \"count-\" (deref class-sig))") " in attr position auto-updates")
|
||||
(li "Side-by-side comparison: effect-based vs continuation-based code")))
|
||||
|
||||
;; =====================================================================
|
||||
;; Multi-Deref Handling
|
||||
;; =====================================================================
|
||||
|
||||
(~docs/section :title "Multi-Deref Handling" :id "multi-deref"
|
||||
|
||||
(~docs/code :code (highlight "(str (deref first-name) \" \" (deref last-name))" "lisp"))
|
||||
|
||||
(ol :class "list-decimal pl-6 mb-6 space-y-3"
|
||||
(li (strong "Initial render:") " First " (code "deref") " hits signal → shifts, captures "
|
||||
(code "(str [HOLE] \" \" (deref last-name))") ". Subscriber registered for "
|
||||
(code "first-name") ". Returns current value. Second " (code "deref")
|
||||
" runs (no ReactiveResetFrame between it and the already-consumed one) — "
|
||||
"falls through to normal scope-based tracking.")
|
||||
(li (strong "first-name changes:") " Subscriber fires → re-pushes ReactiveResetFrame → "
|
||||
"re-invokes continuation with new first-name value → second " (code "deref")
|
||||
" hits ReactiveResetFrame again → shifts, creates NEW subscriber for "
|
||||
(code "last-name") ". Old last-name subscriber cleaned up via sub-scope disposal.")
|
||||
(li (strong "last-name changes:") " Its subscriber fires → re-invokes inner continuation → "
|
||||
"update-fn called with new result."))
|
||||
|
||||
(p "This creates O(n) nested continuations for n derefs. Fine for small reactive expressions."))
|
||||
|
||||
;; =====================================================================
|
||||
;; Commit Strategy
|
||||
;; =====================================================================
|
||||
|
||||
(~docs/section :title "Commit Strategy" :id "commits"
|
||||
|
||||
(ol :class "list-decimal pl-6 mb-4 space-y-1"
|
||||
(li (strong "Commit 1:") " Bootstrap CEK to JS (Step 1) — mechanical, independent")
|
||||
(li (strong "Commit 2:") " ReactiveResetFrame + DerefFrame (Step 2) — new frame types")
|
||||
(li (strong "Commit 3:") " Deref-as-shift + adapter integration + tests (Steps 3-5) — the core change")
|
||||
(li (strong "Commit 4:") " Browser demo (Step 6)")))
|
||||
|
||||
;; =====================================================================
|
||||
;; Files
|
||||
;; =====================================================================
|
||||
|
||||
(~docs/section :title "Files" :id "files"
|
||||
|
||||
(div :class "overflow-x-auto mb-6"
|
||||
(table :class "min-w-full text-sm"
|
||||
(thead (tr
|
||||
(th :class "text-left pr-4 pb-2 font-semibold" "File")
|
||||
(th :class "text-left pb-2 font-semibold" "Change")))
|
||||
(tbody
|
||||
(tr (td :class "pr-4 py-1 font-mono text-xs" "shared/sx/ref/platform_js.py")
|
||||
(td "SPEC_MODULES entries, PLATFORM_CEK_JS, CEK_FIXUPS_JS, SPEC_MODULE_ORDER"))
|
||||
(tr (td :class "pr-4 py-1 font-mono text-xs" "shared/sx/ref/run_js_sx.py")
|
||||
(td "compile_ref_to_js: has_cek, auto-inclusion, ordering, platform code"))
|
||||
(tr (td :class "pr-4 py-1 font-mono text-xs" "shared/sx/ref/js.sx")
|
||||
(td "RENAMES for CEK predicate functions"))
|
||||
(tr (td :class "pr-4 py-1 font-mono text-xs" "shared/sx/ref/bootstrap_py.py")
|
||||
(td "RENAMES for CEK predicates"))
|
||||
(tr (td :class "pr-4 py-1 font-mono text-xs" "shared/sx/ref/frames.sx")
|
||||
(td "ReactiveResetFrame, DerefFrame, has-reactive-reset-frame?, kont-capture-to-reactive-reset"))
|
||||
(tr (td :class "pr-4 py-1 font-mono text-xs" "shared/sx/ref/cek.sx")
|
||||
(td "step-sf-deref, reactive-shift-deref, deref in dispatch, ReactiveResetFrame in step-continue"))
|
||||
(tr (td :class "pr-4 py-1 font-mono text-xs" "shared/sx/ref/adapter-dom.sx")
|
||||
(td "*use-cek-reactive* flag, cek-reactive-attr, cek-reactive-text, conditional dispatch"))
|
||||
(tr (td :class "pr-4 py-1 font-mono text-xs" "shared/sx/ref/test-cek-reactive.sx")
|
||||
(td (strong "New:") " continuation-based reactivity tests"))
|
||||
(tr (td :class "pr-4 py-1 font-mono text-xs" "shared/sx/ref/run_cek_reactive_tests.py")
|
||||
(td (strong "New:") " Python test runner"))
|
||||
(tr (td :class "pr-4 py-1 font-mono text-xs" "shared/sx/ref/sx_ref.py")
|
||||
(td "Rebootstrap (generated)"))
|
||||
(tr (td :class "pr-4 py-1 font-mono text-xs" "shared/static/scripts/sx-browser.js")
|
||||
(td "Rebootstrap (generated)"))))))
|
||||
|
||||
;; =====================================================================
|
||||
;; Risks
|
||||
;; =====================================================================
|
||||
|
||||
(~docs/section :title "Risks" :id "risks"
|
||||
|
||||
(ol :class "list-decimal pl-6 mb-4 space-y-2"
|
||||
(li (strong "Performance:") " CEK allocates a dict per step. Mitigated: opt-in flag, tree-walk remains default.")
|
||||
(li (strong "Multi-deref stale subscribers:") " Mitigated: sub-scope disposal before re-invocation.")
|
||||
(li (strong "Interaction with user shift/reset:") " " (code "kont-capture-to-reactive-reset")
|
||||
" only scans for " (code "\"reactive-reset\"") ", not " (code "\"reset\"") ". Orthogonal.")
|
||||
(li (strong "JS bootstrapper complexity:") " ~10 RENAMES for predicates. Default mangling handles the rest.")))))
|
||||
@@ -578,6 +578,7 @@
|
||||
"sx-protocol" (~plans/sx-protocol/plan-sx-protocol-content)
|
||||
"scoped-effects" (~plans/scoped-effects/plan-scoped-effects-content)
|
||||
"foundations" (~plans/foundations/plan-foundations-content)
|
||||
"cek-reactive" (~plans/cek-reactive/plan-cek-reactive-content)
|
||||
:else (~plans/index/plans-index-content))))
|
||||
|
||||
;; ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user