host: cards-as-objects import + typing reads direct KV edges (composition step 5 + perf)
STEP 5 (cards-as-objects). The importer no longer carries a Ghost body as one opaque sx_content string: host/blog--decompose! splits an (article …) into one stored card OBJECT per top-level block (is-a the mapped card-type + its field-values), links each by an ordered `contains` edge, and sets the post :body = (seq (ref c0) (ref c1) …). Card types now carry a render :template, so the new `ref` combinator (compose.sx) transcludes each card via the SAME typed-block path articles use. /import wired to decompose; the home index filtered to published so the "block"-status card objects stay hidden. Added the `val` leaf (raw field value, no <span>) for attribute interpolation in templates (href/src). The post page renders the transcluded cards — verified end-to-end (conformance 157/159; the 2 fails are the pre-existing relate-picker pagination pair, unrelated). PERF (the conformance-speed fix). host/blog typing — types-of / instances-of / type-defs — computed the subtype closure via lib/relations descendants/ancestors, and EVERY such call re-saturates the whole CEK-interpreted Datalog ruleset (~seconds each). Typing is the hottest path (is-a?/types-of/instances-of run per post, per picker, per render), so this dominated both the blog suite and live page latency. Now the closure is a host-side BFS over the DIRECT subtype-of edges (the edge:* KV rows, via host/blog--subtype-closure) — one snapshot per closure, O(edges), cycle-safe, Datalog-free. Same transitive set (KV == relations for direct edges, host/blog-relate! writes both), so exact, not approximate. Drops Datalog out of the typing hot path entirely — speeds conformance AND the live site (/tags etc.). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -106,9 +106,18 @@ Transclusion = a `ref` leaf. Sort/filter/limit/group = the *source query* langua
|
||||
self-contained — it asks the context for the data; the host supplies graph access. The
|
||||
list isn't baked into the body; it's whatever is-a TYPE *right now*. (`/compose-demo`
|
||||
each is now a live query over seeded `compose-item` instances.)
|
||||
4. Live context: route auth/device/locale into the context; reactive values later.
|
||||
5. The typed importer decomposes Ghost Lexical into card objects + a `contains` body (cards-as-
|
||||
objects), instead of one `sx_content` string.
|
||||
4. **(done)** Live context: `host/blog--comp-ctx` routes auth + device (User-Agent) + locale
|
||||
(Accept-Language) — read purely from the request — into the render context, so the SAME
|
||||
object renders a responsive/personalised variant (`(alt (when (eq "device" "mobile") …) …)`).
|
||||
Reactive values plug into the same context later with no new combinators.
|
||||
5. **(done)** The typed importer decomposes content into card OBJECTS + a `contains` body
|
||||
(cards-as-objects), instead of one `sx_content` string. `host/blog--decompose!` splits an
|
||||
`(article …)` into one stored card object per block (is-a a card-type + field-values),
|
||||
linked by ordered `contains` edges, with `:body = (seq (ref c0) (ref c1) …)`. Card types
|
||||
carry a render `:template`, so the `ref` combinator transcludes each card via the existing
|
||||
typed-block path. `/import` wired; home filtered to published so `"block"` cards stay hidden.
|
||||
The `val` (raw value) leaf added for attribute interpolation. (Perf: typing now reads direct
|
||||
KV `subtype-of` edges via a host-side BFS, not lib/relations — no Datalog re-saturation.)
|
||||
6. The block editor edits the body (insert/reorder/`alt`/`each`) — the metamodel editor for content.
|
||||
7. **Prove universality with a second fold.** Write a tiny `execute`-fold over the *same*
|
||||
`seq/alt/each` structure that *runs* a workflow (leaves = effects; `seq` = steps in order, `alt`
|
||||
|
||||
Reference in New Issue
Block a user