Phase 7b: page render plans — per-page boundary optimizer
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>
This commit is contained in:
@@ -49,7 +49,7 @@
|
||||
|
||||
;; --- Main page component ---
|
||||
|
||||
(defcomp ~affinity-demo-content (&key components)
|
||||
(defcomp ~affinity-demo-content (&key components page-plans)
|
||||
(div :class "space-y-8"
|
||||
(div :class "border-b border-stone-200 pb-6"
|
||||
(h1 :class "text-2xl font-bold text-stone-900" "Affinity Annotations")
|
||||
@@ -154,6 +154,35 @@
|
||||
(td :class "px-3 py-2 font-bold text-orange-700" "server")
|
||||
(td :class "px-3 py-2 text-stone-600" "Both affinity and IO say server"))))))
|
||||
|
||||
;; Per-page render plans
|
||||
(~doc-section :title "Page Render Plans" :id "plans"
|
||||
(p "Phase 7b: render plans are pre-computed at registration time for each page. The plan maps every component needed by the page to its render target.")
|
||||
|
||||
(when (> (len page-plans) 0)
|
||||
(div :class "space-y-4 mt-4"
|
||||
(map (fn (plan)
|
||||
(div :class "rounded border border-stone-200 p-4"
|
||||
(div :class "flex items-center justify-between mb-3"
|
||||
(div
|
||||
(span :class "font-mono font-medium text-stone-800" (get plan "name"))
|
||||
(span :class "text-stone-400 ml-2 text-sm" (get plan "path")))
|
||||
(div :class "flex gap-2"
|
||||
(span :class "inline-block px-2 py-0.5 rounded text-xs font-bold bg-orange-100 text-orange-700"
|
||||
(str (get plan "server-count") " server"))
|
||||
(span :class "inline-block px-2 py-0.5 rounded text-xs font-bold bg-green-100 text-green-700"
|
||||
(str (get plan "client-count") " client"))))
|
||||
(when (> (get plan "server-count") 0)
|
||||
(div :class "mb-2"
|
||||
(span :class "text-xs font-medium text-stone-500 uppercase" "Server-expanded: ")
|
||||
(span :class "text-sm font-mono text-orange-700"
|
||||
(join " " (get plan "server")))))
|
||||
(when (> (get plan "client-count") 0)
|
||||
(div
|
||||
(span :class "text-xs font-medium text-stone-500 uppercase" "Client-rendered: ")
|
||||
(span :class "text-sm font-mono text-green-700"
|
||||
(join " " (get plan "client")))))))
|
||||
page-plans))))
|
||||
|
||||
;; How it integrates
|
||||
(~doc-section :title "How It Works" :id "how"
|
||||
(ol :class "list-decimal list-inside text-stone-700 space-y-2"
|
||||
|
||||
@@ -2014,8 +2014,30 @@
|
||||
(li "Backward compatible: existing defcomp without :affinity defaults to \"auto\""))))
|
||||
|
||||
(~doc-subsection :title "7b. Runtime Boundary Optimizer"
|
||||
|
||||
(div :class "rounded border border-green-300 bg-green-50 p-3 mb-4"
|
||||
(div :class "flex items-center gap-2 mb-1"
|
||||
(span :class "inline-block px-2 py-0.5 rounded text-xs font-bold bg-green-600 text-white uppercase" "Complete"))
|
||||
(p :class "text-green-800 text-sm" "Per-page render plans computed at registration time. Each page knows exactly which components render server-side vs client-side, cached on PageDef."))
|
||||
|
||||
(p "Given component tree + IO dependency graph + affinity annotations, decide per-component: server-expand, client-render, or stream. Planning step cached at registration, recomputed on component change.")
|
||||
(p :class "text-stone-500 text-sm italic" "Next: integrate render-target into the bundle analyzer, page registry, and orchestration.sx."))
|
||||
|
||||
(p (code "page-render-plan") " in deps.sx computes per-page boundary decisions:")
|
||||
(~doc-code :code (highlight "(page-render-plan page-source env io-names)\n;; Returns:\n;; {:components {~name \"server\"|\"client\" ...}\n;; :server (list of server-expanded names)\n;; :client (list of client-rendered names)\n;; :io-deps (IO primitives needed by server components)}" "lisp"))
|
||||
|
||||
(~doc-subsection :title "Integration Points"
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1"
|
||||
(li (code "shared/sx/ref/deps.sx") " — " (code "page-render-plan") " spec function")
|
||||
(li (code "shared/sx/deps.py") " — Python wrapper, dispatches to bootstrapped code")
|
||||
(li (code "shared/sx/pages.py") " — " (code "compute_page_render_plans()") " called at mount time, caches on PageDef")
|
||||
(li (code "shared/sx/helpers.py") " — " (code "_build_pages_sx()") " includes " (code ":render-plan") " in client page registry")
|
||||
(li (code "shared/sx/types.py") " — " (code "PageDef.render_plan") " field")))
|
||||
|
||||
(~doc-subsection :title "Verification"
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1"
|
||||
(li "5 new spec tests (page-render-plan suite)")
|
||||
(li "Render plans visible on " (a :href "/isomorphism/affinity" "affinity demo page"))
|
||||
(li "Client page registry includes :render-plan for each page"))))
|
||||
|
||||
(~doc-subsection :title "7c. Optimistic Data Updates"
|
||||
(p "Extend existing apply-optimistic/revert-optimistic in engine.sx from DOM-level to data-level. Client updates cached data optimistically, sends mutation to server, reverts on rejection."))
|
||||
|
||||
@@ -881,9 +881,10 @@ async def _streaming_demo_data():
|
||||
|
||||
|
||||
def _affinity_demo_data() -> dict:
|
||||
"""Return affinity analysis for the demo components."""
|
||||
"""Return affinity analysis for the demo components + page render plans."""
|
||||
from shared.sx.jinja_bridge import get_component_env
|
||||
from shared.sx.types import Component
|
||||
from shared.sx.pages import get_all_pages
|
||||
|
||||
env = get_component_env()
|
||||
demo_names = [
|
||||
@@ -904,4 +905,20 @@ def _affinity_demo_data() -> dict:
|
||||
"io-refs": sorted(val.io_refs),
|
||||
"is-pure": val.is_pure,
|
||||
})
|
||||
return {"components": components}
|
||||
|
||||
# Collect render plans from all sx service pages
|
||||
page_plans = []
|
||||
for page_def in get_all_pages("sx").values():
|
||||
plan = page_def.render_plan
|
||||
if plan:
|
||||
page_plans.append({
|
||||
"name": page_def.name,
|
||||
"path": page_def.path,
|
||||
"server-count": len(plan.get("server", [])),
|
||||
"client-count": len(plan.get("client", [])),
|
||||
"server": plan.get("server", []),
|
||||
"client": plan.get("client", []),
|
||||
"io-deps": plan.get("io-deps", []),
|
||||
})
|
||||
|
||||
return {"components": components, "page-plans": page_plans}
|
||||
|
||||
Reference in New Issue
Block a user