A tag is just a post that is-a tag; tagging is a "tagged" edge to it. End to end: mark a post a tag, tag posts with it, see a post's tags and a tag's members. - helpers: host/blog-is-tag? (= is-a? slug "tag"), host/blog-tags (out tagged), host/blog-tagged-with (in tagged), host/blog-instances-of (a type's members, O(#subtypes) not O(#posts) — the efficient candidate source). - picker generalised to be KIND-AWARE and MULTI-INSTANCE: relate-options takes &kind=, candidates come from the kind's registry :candidates (all/tags/types); /relate-picker.js wires every .relate-picker box by data-kind (a Related picker and a Tags picker now coexist on the edit page). - render: post page gains a "Tags" block; a tag post additionally lists "Tagged with this" (its members). edit page: a Related editor + a Tags editor + an "is this post a tag" toggle (reuses /relate kind=is-a — no new route). - GOTCHA (again): host/blog--relation-editor read host/blog-out INSIDE its quasiquote -> VmSuspended/500 under http-listen + durable edges; moved the read to a let before the quasiquote (conformance can't see it — in-memory store; the ephemeral Playwright run caught it). 6 conformance tests (is-tag?, instances-of, tag+tagged-with, tagged picker offers only tags, related picker still all, is-a-tag toggle) -> 261/261. Playwright multi-picker 4/4. Verified live: ocaml made a tag, welcome tagged ocaml, Tags block + Tagged-with-this both render. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
21 KiB
21 KiB