host: SX-native wire — reads + write bodies are text/sx, JSON CRUD deleted

Greenfield SX-native pivot (NOT a strangler): the host speaks SX/SXTP end to end;
JSON only at the future ActivityPub federation edge.

- OUTPUT: host/json-status -> host/sx-status — every host/ok/host/error response is
  text/sx via the serialize primitive (NOT application/json). Flips feed, relations,
  blog reads. Tests assert the SX envelope ({:ok true :data ...}).
- DELETE the blog JSON CRUD /posts (POST/PUT/DELETE) + bearer-based host/blog--protect:
  a pure old-contract REST mirror. Create/edit go through the HTML editor forms;
  programmatic writes speak SXTP. FOLLOW-UP: no browser delete route yet (was JSON-only,
  no UI) — add POST /:slug/delete + cascade edge cleanup when the metamodel UI needs it.
- INPUT: host/sx-body (sxtp.sx) parses a text/sx request body to a string-keyed dict
  (parse-safe + sxtp/-normalize). feed POST + relations attach/detach read it.
- UNIFIED field reader host/fields / host/field: text/sx body OR urlencoded form by
  content-type. The blog form handlers (new/edit/relate/unrelate) + login read through
  it — additive, urlencoded still works (no-engine / bootstrap fallback).

Conformance 290/290 (11 suites). Retires the strangler framing in the plan; adds the
'SX all the way out' wire table. The engine half (browser posts text/sx) follows.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-30 11:07:30 +00:00
parent ad86f3051e
commit 999249b944
14 changed files with 145 additions and 221 deletions

View File

@@ -25,11 +25,11 @@
;; ── write ──────────────────────────────────────────────────────────
;; POST /feed -> create an activity from the JSON body. Returns 201 + the created
;; (normalised) activity. Body must be a JSON object; anything else -> 400.
;; POST /feed -> create an activity from the text/sx body. Returns 201 + the created
;; (normalised) activity. Body must be an SX dict; anything else -> 400.
(define host/feed-create
(fn (req)
(let ((raw (dream-json-body req)))
(let ((raw (host/sx-body req)))
(if (= (type-of raw) "dict")
(host/ok-status 201 (feed/post raw))
(host/error 400 "invalid activity")))))