host: Phase 2 complete — SXTP wire format + Dream bridge, 82/82
lib/host/sxtp.sx implements the host<->subsystem wire format per
applications/sxtp/spec.sx:
- message algebra (request/response/condition/event + status helpers
ok/created/not-found/forbidden/invalid/fail) as string-keyed dicts;
verb/status/type stored as symbols (ride the wire bare)
- codec: sxtp/serialize (dict -> text/sx list form, deterministic top-level
field order, nested messages emitted in their own list form, no :msg leak)
and sxtp/parse (text/sx -> dict via a deep keyword-token->string normaliser)
- Dream bridge: sxtp/from-dream (HTTP req -> SXTP req, method->verb,
query->params) and sxtp/to-dream (SXTP resp -> HTTP resp, status->code,
body serialised to text/sx)
- 39-test suite covering algebra, serialise/parse round-trip, mappings, bridge
Runtime notes: serialize renders string-keyed dicts as {:k v} and symbols
bare; parsed keyword tokens are a distinct type (not = to string literals) so
parse normalises; unquote-splicing is unreliable so the emitter is str-based.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -36,8 +36,8 @@ host — no `ocaml-on-sx` dependency.
|
||||
|
||||
## Status (rolling)
|
||||
|
||||
`bash lib/host/conformance.sh` → **43/43** (4 suites: handler, middleware, router,
|
||||
feed). Phase 1 DONE; Phase 2 in progress (middleware + write endpoint DONE, SXTP next).
|
||||
`bash lib/host/conformance.sh` → **82/82** (5 suites: handler, middleware, sxtp,
|
||||
router, feed). Phases 1 & 2 DONE; Phase 3 (strangler ledger) next.
|
||||
|
||||
## Ground rules
|
||||
|
||||
@@ -91,8 +91,15 @@ lib/host/sxtp.sx subsystem APIs (feed/search/commerce/…
|
||||
INJECTED resource extractor), `host/pipeline` (first = outermost). Reuses
|
||||
Dream's `dream-bearer-token` + `dream-catch-with`; calls lib/acl public API.
|
||||
Mute/prefs layer deferred (no blocker, add when a domain needs it).
|
||||
- [ ] `sxtp.sx` — host↔subsystem wire format (align with existing spec at
|
||||
`applications/sxtp/spec.sx`)
|
||||
- [x] `sxtp.sx` — host↔subsystem wire format (per `applications/sxtp/spec.sx`).
|
||||
Message algebra (`sxtp/request`/`response`/`condition`/`event` + status
|
||||
helpers `sxtp/ok`/`created`/`not-found`/`forbidden`/`invalid`/`fail`) as
|
||||
string-keyed dicts; verb/status/type as symbols (ride the wire bare). Codec:
|
||||
`sxtp/serialize` (dict → `text/sx` list form, deterministic field order,
|
||||
nested messages in their own list form, no `:msg` leak) and `sxtp/parse`
|
||||
(`text/sx` → dict, deep keyword-token→string normaliser). Dream bridge:
|
||||
`sxtp/from-dream` (HTTP req → SXTP req, method→verb, query→params) and
|
||||
`sxtp/to-dream` (SXTP resp → HTTP resp, status→code, body→`text/sx`).
|
||||
- [x] migrate a write endpoint (auth + permission + action): `POST /feed`
|
||||
(`host/feed-write-routes resolve`) — auth ∘ ACL("post","feed") ∘ wrap-errors
|
||||
over `host/feed-create`, which parses the JSON body and `feed/post`s it (201);
|
||||
@@ -133,8 +140,19 @@ lib/host/sxtp.sx subsystem APIs (feed/search/commerce/…
|
||||
against lib/acl's public `acl/permit?` (string atoms work — no symbol coercion
|
||||
needed). The write path proves the auth ∘ permission ∘ action stack end-to-end:
|
||||
401 unauth, 403 unpermitted, 201 + readback on success, 400 on bad body.
|
||||
- **Remaining for Phase 2: `sxtp.sx`** — the host↔subsystem wire format. Align
|
||||
with the existing spec at `applications/sxtp/spec.sx`. This is the next tick.
|
||||
- **Phase 2 COMPLETE (82/82).** `lib/host/sxtp.sx` adds the SXTP codec + Dream
|
||||
bridge (39-test suite). Key representation calls, learned by probing the runtime:
|
||||
keywords are strings at eval time but the `serialize` primitive renders
|
||||
string-keyed dicts back as `{:k v}` and symbols bare — so messages are
|
||||
string-keyed dicts with verb/status/type as symbols, and a small str-based
|
||||
emitter produces wire-faithful list form. `parse` needs a deep normaliser
|
||||
because parsed keyword tokens are a distinct type (not `=` to string literals).
|
||||
`unquote-splicing` is unreliable here, so the serializer is str-based, not
|
||||
quasiquote-based.
|
||||
- **Next: Phase 3 — strangler migration ledger.** Enumerate the Quart endpoints
|
||||
(use the `rose-ash-services` `svc_routes` MCP tool), track migrated vs proxied,
|
||||
and stand up a golden-response harness against the live Quart responses. Then
|
||||
cut over the smallest whole domain (`likes` or `relations`) as proof.
|
||||
|
||||
## Blockers
|
||||
|
||||
|
||||
Reference in New Issue
Block a user