host: relations-as-posts slice 2 — relation metadata lives on relation-posts
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 48s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 48s
is-a/subtype-of/tagged/related are now POSTS (each is-a a new `relation` root),
owning their metadata in a :rel slot {:symmetric :label :inverse-label}. The static
host/blog-rel-kinds registry is gone: kind-spec/rel-kinds/kind-symmetric? read the
relation-posts (via an in-memory cache), and the relation list derives from
host/blog-in "relation" "is-a".
Perform-budget fixes (a durable read inside the http-listen render VM raises
VmSuspended; too many per request 500s the page):
- relation metadata is loaded into a cache at boot (host/blog-load-rel-kinds!,
like load-edges!), so kind-spec is pure on render paths;
- the initial edit page renders its pickers EMPTY (the load trigger fills each) —
only the relate/unrelate FRAGMENT server-renders candidates (with-cands flag).
Previously every edit page render did candidate-get × 4 pickers and 500'd.
host conformance 287/287 (+4 slice-2: kind-spec reads :rel, kind-symmetric? off the
post, unknown kind has no spec, rel-kinds derived from the graph). run-picker-check
3/3 (edit page boots, relate/unrelate flow works, no client errors).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -213,6 +213,11 @@
|
||||
|
||||
;; -- relate posts (blog × relations) --
|
||||
;; my-first-post and another-one both exist in the write-test store at this point.
|
||||
;; Relations are posts now (their symmetry/labels live on relation-posts), so seed
|
||||
;; them up front exactly as boot does (serve.sh) before exercising relate, and load
|
||||
;; the relation metadata into the in-memory cache the same way.
|
||||
(host/blog-seed-types!)
|
||||
(host/blog-load-rel-kinds!)
|
||||
(host-bl-test "relate no auth -> redirect to login"
|
||||
(dream-status (host-bl-wapp (host-bl-send "POST" "/my-first-post/relate" nil
|
||||
"application/x-www-form-urlencoded" "other=another-one"))) 303)
|
||||
@@ -276,7 +281,7 @@
|
||||
;; "load" and on debounced "input". The SX engine re-binds these triggers on
|
||||
;; swapped content, so it works on a full load AND a boosted SPA nav.
|
||||
(host-bl-test "picker form is declaratively wired to relate-options (load + debounced input)"
|
||||
(let ((html (render-page (host/blog--relation-editor "alpha-post" "related"))))
|
||||
(let ((html (render-page (host/blog--relation-editor "alpha-post" "related" true))))
|
||||
(list (contains? html "/alpha-post/relate-options")
|
||||
(contains? html "input delay:200ms, load")
|
||||
(contains? html "rp-related-results")))
|
||||
@@ -285,7 +290,7 @@
|
||||
;; <ul>, so a re-rendered editor is never briefly empty (no flash). The candidate row
|
||||
;; for an existing post appears inside the results ul.
|
||||
(host-bl-test "editor server-renders the first page of candidates into the picker"
|
||||
(let ((html (render-page (host/blog--relation-editor "alpha-post" "related"))))
|
||||
(let ((html (render-page (host/blog--relation-editor "alpha-post" "related" true))))
|
||||
(list (contains? html "id=\"cand-related-") ;; a candidate row is present
|
||||
(contains? html "Beta Post"))) ;; an unrelated post is offered
|
||||
(list true true))
|
||||
@@ -313,7 +318,7 @@
|
||||
(host/blog-relate! "alpha-post" "beta-post" "related")
|
||||
;; the editor wraps current list + picker in #rel-editor-KIND; remove re-renders it
|
||||
(host-bl-test "relation-editor wires remove to re-render the kind's editor"
|
||||
(let ((html (render-page (host/blog--relation-editor "alpha-post" "related"))))
|
||||
(let ((html (render-page (host/blog--relation-editor "alpha-post" "related" true))))
|
||||
(list (contains? html "id=\"rel-editor-related\"") ;; the swap target
|
||||
(contains? html "sx-post=\"/alpha-post/unrelate\"") ;; AJAX, not plain post
|
||||
(contains? html "sx-target=\"#rel-editor-related\"")
|
||||
@@ -481,6 +486,22 @@
|
||||
(contains? (dream-resp-body (host-bl-app (host-bl-req "/ppost/relate-options?kind=is-a"))) "Article")
|
||||
true)
|
||||
|
||||
;; -- relations are posts: symmetry + labels read off the relation-posts (slice 2) --
|
||||
(host-bl-test "kind-spec reads :rel metadata off the relation-post"
|
||||
(let ((s (host/blog--kind-spec "is-a")))
|
||||
(list (get s :kind) (get s :label) (get s :symmetric) (get s :inverse-label)))
|
||||
(list "is-a" "Types" false "Instances"))
|
||||
(host-bl-test "kind-symmetric? reads symmetry off the post (related yes, is-a no)"
|
||||
(list (host/blog--kind-symmetric? "related") (host/blog--kind-symmetric? "is-a"))
|
||||
(list true false))
|
||||
(host-bl-test "an unknown kind has no spec, so relate still validates it away"
|
||||
(host/blog--kind-spec "bogus-kind") nil)
|
||||
(host-bl-test "rel-kinds is DERIVED from the graph (every post that is-a relation)"
|
||||
(let ((kinds (map (fn (s) (get s :kind)) (host/blog-rel-kinds))))
|
||||
(list (contains? kinds "related") (contains? kinds "is-a")
|
||||
(contains? kinds "subtype-of") (contains? kinds "tagged")))
|
||||
(list true true true true))
|
||||
|
||||
;; -- Phase 3: tags as posts -- (ocaml is-a tag, from the seed-types test above)
|
||||
(host-bl-test "is-tag?: a post that is-a tag is a tag; others are not"
|
||||
(list (host/blog-is-tag? "ocaml") (host/blog-is-tag? "ppost"))
|
||||
|
||||
Reference in New Issue
Block a user