From 6215d3573bc52b0106a4e8225ef4582d79ec12a2 Mon Sep 17 00:00:00 2001 From: giles Date: Sat, 7 Mar 2026 08:35:20 +0000 Subject: [PATCH 1/3] Send content expression component deps in SX responses for client routing When a page has a content expression but no data dependency, compute its transitive component deps and pass them as extra_component_names to sx_response(). This ensures the client has all component definitions needed for future client-side route rendering. Co-Authored-By: Claude Opus 4.6 --- shared/sx/helpers.py | 22 +++++++++++++++++++--- shared/sx/pages.py | 14 +++++++++++++- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/shared/sx/helpers.py b/shared/sx/helpers.py index 3174184..659ac9f 100644 --- a/shared/sx/helpers.py +++ b/shared/sx/helpers.py @@ -456,7 +456,8 @@ def sx_call(component_name: str, **kwargs: Any) -> str: -def components_for_request(source: str = "") -> str: +def components_for_request(source: str = "", + extra_names: set[str] | None = None) -> str: """Return defcomp/defmacro source for definitions the client doesn't have yet. Reads the ``SX-Components`` header (comma-separated component names @@ -464,6 +465,10 @@ def components_for_request(source: str = "") -> str: is missing. If *source* is provided, only sends components needed for that source (plus transitive deps). If the header is absent, returns all needed defs. + + *extra_names* — additional component names (``~foo``) to include + beyond what *source* references. Used by ``execute_page`` to send + components the page's content expression needs for client-side routing. """ from quart import request from .jinja_bridge import _COMPONENT_ENV @@ -477,6 +482,12 @@ def components_for_request(source: str = "") -> str: else: needed = None # all + # Merge in extra names (e.g. from page content expression deps) + if extra_names and needed is not None: + needed = needed | extra_names + elif extra_names: + needed = extra_names + loaded_raw = request.headers.get("SX-Components", "") loaded = set(loaded_raw.split(",")) if loaded_raw else set() @@ -510,7 +521,8 @@ def components_for_request(source: str = "") -> str: def sx_response(source: str, status: int = 200, - headers: dict | None = None): + headers: dict | None = None, + extra_component_names: set[str] | None = None): """Return an s-expression wire-format response. Takes a raw sx string:: @@ -520,6 +532,10 @@ def sx_response(source: str, status: int = 200, For SX requests, missing component definitions are prepended as a ``\n{body}') diff --git a/shared/sx/pages.py b/shared/sx/pages.py index 8912808..2c1ee1a 100644 --- a/shared/sx/pages.py +++ b/shared/sx/pages.py @@ -279,13 +279,25 @@ async def execute_page( is_htmx = is_htmx_request() if is_htmx: + # Compute content expression deps so the server sends component + # definitions the client needs for future client-side routing + extra_deps: set[str] | None = None + if page_def.content_expr is not None and page_def.data_expr is None: + from .deps import components_needed + from .parser import serialize + try: + content_src = serialize(page_def.content_expr) + extra_deps = components_needed(content_src, get_component_env()) + except Exception: + pass # non-critical — client will just fall back to server + return sx_response(await oob_page_sx( oobs=oob_headers if oob_headers else "", filter=filter_sx, aside=aside_sx, content=content_sx, menu=menu_sx, - )) + ), extra_component_names=extra_deps) else: return await full_page_sx( tctx, From feb368f7fbb93678e897a3e5d0732de52b0903ae Mon Sep 17 00:00:00 2001 From: giles Date: Sat, 7 Mar 2026 08:35:27 +0000 Subject: [PATCH 2/3] Add plans audit: status overview + fragment protocol, glue decoupling, social sharing pages Audit all plan files and create documentation pages for what remains: - Status overview with green/amber/stone badges for all 15 plans - Fragment Protocol: what exists (GET), what remains (POST sexp, structured response) - Glue Decoupling: 25+ cross-app imports to eliminate via glue service layer - Social Sharing: 6-phase OAuth-based sharing to major platforms Co-Authored-By: Claude Opus 4.6 --- sx/sx/nav-data.sx | 10 +- sx/sx/plans.sx | 277 +++++++++++++++++++++++++++++++++++++++++++ sx/sxc/pages/docs.sx | 4 + 3 files changed, 290 insertions(+), 1 deletion(-) diff --git a/sx/sx/nav-data.sx b/sx/sx/nav-data.sx index 29f34eb..998db1b 100644 --- a/sx/sx/nav-data.sx +++ b/sx/sx/nav-data.sx @@ -109,10 +109,18 @@ (dict :label "Routing Analyzer" :href "/isomorphism/routing-analyzer"))) (define plans-nav-items (list + (dict :label "Status" :href "/plans/status" + :summary "Audit of all plans — what's done, what's in progress, and what remains.") (dict :label "Reader Macros" :href "/plans/reader-macros" :summary "Extensible parse-time transformations via # dispatch — datum comments, raw strings, and quote shorthand.") (dict :label "SX-Activity" :href "/plans/sx-activity" - :summary "A new web built on SX — executable content, shared components, parsers, and logic on IPFS, provenance on Bitcoin, all running within your own security context."))) + :summary "A new web built on SX — executable content, shared components, parsers, and logic on IPFS, provenance on Bitcoin, all running within your own security context.") + (dict :label "Fragment Protocol" :href "/plans/fragment-protocol" + :summary "Structured sexp request/response for cross-service component transfer.") + (dict :label "Glue Decoupling" :href "/plans/glue-decoupling" + :summary "Eliminate all cross-app model imports via glue service layer.") + (dict :label "Social Sharing" :href "/plans/social-sharing" + :summary "OAuth-based sharing to Facebook, Instagram, Threads, Twitter/X, LinkedIn, and Mastodon."))) (define bootstrappers-nav-items (list (dict :label "Overview" :href "/bootstrappers/") diff --git a/sx/sx/plans.sx b/sx/sx/plans.sx index 059977d..17a7338 100644 --- a/sx/sx/plans.sx +++ b/sx/sx/plans.sx @@ -594,6 +594,283 @@ (td :class "px-3 py-2 text-stone-700" "Content addressing — shared with component CIDs") (td :class "px-3 py-2 text-stone-600" "2, 3")))))))) +;; --------------------------------------------------------------------------- +;; Plan Status Overview +;; --------------------------------------------------------------------------- + +(defcomp ~plan-status-content () + (~doc-page :title "Plan Status" + + (p :class "text-lg text-stone-600 mb-6" + "Audit of all plans across the SX language and Rose Ash platform. Last updated March 2026.") + + ;; ----------------------------------------------------------------------- + ;; Completed + ;; ----------------------------------------------------------------------- + + (~doc-section :title "Completed" :id "completed" + + (div :class "space-y-4" + + (div :class "rounded border border-green-200 bg-green-50 p-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") + (span :class "font-semibold text-stone-800" "Split Cart into Microservices")) + (p :class "text-sm text-stone-600" "Cart decomposed into 4 services: relations (internal, owns ContainerRelation), likes (internal, unified generic likes), orders (public, owns Order/OrderItem + SumUp checkout), and cart (thin CartItem CRUD). All three new services deployed with dedicated databases.")) + + (div :class "rounded border border-green-200 bg-green-50 p-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") + (span :class "font-semibold text-stone-800" "Ticket Purchase Through Cart")) + (p :class "text-sm text-stone-600" "Tickets flow through the cart like products: state=pending in cart, reserved at checkout, confirmed on payment. TicketDTO, CartSummaryDTO with ticket_count/ticket_total, CalendarService protocol methods all implemented.")) + + (div :class "rounded border border-green-200 bg-green-50 p-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") + (span :class "font-semibold text-stone-800" "Ticket UX Improvements")) + (p :class "text-sm text-stone-600" "+/- quantity buttons on entry pages and cart. Tickets grouped by event in cart display. Adjust quantity route, sold/basket counts, matching product card UX pattern.")) + + (div :class "rounded border border-green-200 bg-green-50 p-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") + (a :href "/isomorphism/" :class "font-semibold text-green-800 underline" "Isomorphic Phase 1: Dependency Analysis")) + (p :class "text-sm text-stone-600" "Per-page component bundles via deps.sx. Transitive closure, scan-refs, components-needed, page-css-classes. 15 tests, bootstrapped to both hosts.")) + + (div :class "rounded border border-green-200 bg-green-50 p-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") + (a :href "/isomorphism/" :class "font-semibold text-green-800 underline" "Isomorphic Phase 2: IO Detection")) + (p :class "text-sm text-stone-600" "Automatic IO classification. scan-io-refs, transitive-io-refs, compute-all-io-refs. Server expands IO components, serializes pure ones for client.")) + + (div :class "rounded border border-green-200 bg-green-50 p-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") + (a :href "/isomorphism/" :class "font-semibold text-green-800 underline" "Isomorphic Phase 3: Client-Side Routing")) + (p :class "text-sm text-stone-600" "router.sx spec, page registry via