host: blog post CRUD (list/create/update/delete) + fail-loud test runner, 175/175
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 37s

CRUD on the durable content store, per-request IO:
  GET  /posts        list (public)            -> [{slug,title}]
  GET  /<slug>/      read (public)            -> HTML / 404
  POST /posts        create (auth+ACL edit/blog) -> 201/400/409
  PUT  /posts/<slug> update title+body        -> 200/400/404
  DELETE /posts/<slug> delete (truncate)      -> 200/404
Writes behind the auth+ACL pipeline; create=insert ops, update=op-updates,
delete=stream truncate. 16 new CRUD tests (full lifecycle + 401/403/409/404).

GOTCHA fixed:  is a reserved CEK special form — a (let ((guard ...)))
helper was shadowed by it ((guard h) ran the guard special form -> 'first:
expected list'). Renamed to host/blog--protect; namespace-prefix all helpers.

HARDENING: conformance.sh now FAILS LOUD on load/eval errors. A test file that
errors mid-load silently truncates its suite and reports a false green (this hid
the CRUD failure as 'blog 13 passed, 0 failed'). The runner greps for error
markers and aborts. Documented the SX gotcha set + prevention ladder in the plan.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-19 19:24:59 +00:00
parent 7c11d4edaa
commit 85e0af83f6
4 changed files with 248 additions and 23 deletions

View File

@@ -288,6 +288,32 @@ lib/host/sxtp.sx subsystem APIs (feed/search/commerce/…
(docker stack + Caddy) remains. NEXT: golden harness, internal-HMAC, then promote
into the stack behind a fresh subdomain.
## SX gotchas + how this loop guards against them
The SX dev experience has real footguns. Most are statically detectable; the
tools exist (`sx_validate`, `deps-check`, `sx_format_check`) but must be *gated*.
Hit/relevant here:
- **Reserved-name shadowing** — `guard`/`bind`/`conj`/`disj` are special forms or
host primitives; a local binding of that name is silently shadowed by the form.
(`(let ((guard ...)))` made `(guard handler)` invoke the R7RS `guard` special
form → `first: expected list`.) Fix: namespace-prefix every helper
(`host/blog--protect`, never `guard`).
- **Silent test truncation** — a test file that errors mid-load returns only the
tests that ran before the error, reporting a FALSE GREEN ("blog 13 passed, 0
failed" while 16 CRUD tests never ran). **GUARDED**: `conformance.sh` now greps
the run output for `Undefined symbol` / `Unhandled exception` / `expected list,
got` / `[load] … error` and aborts loudly before the tally can hide it.
- **`let` is parallel** (bindings can't see each other), **bodies need `(do …)`**
(only the last expr evaluates), **`append!` no-ops on map/rest-derived lists**,
**parsed keyword tokens ≠ string literals**. These produce wrong *results*, so
test coverage catches them as red (not silent) — provided the runner is honest,
which the truncation guard now ensures.
Prevention ladder: parse (`sx_validate` after every edit) → unresolved/shadowed
symbols (`deps-check`, candidate pre-commit gate) → fail-loud runner (done) →
behavioural tests. A `deps-check`-style "binding shadows a special form" lint
would catch the reserved-name class before runtime — a worthwhile follow-up.
## Blockers
- **Live wiring to the native OCaml HTTP server** (Phase 3/4): the prod server in