host: malformed posts degrade instead of 502 (parse-safe + 500 boundary)

A post whose sx_content is malformed SX (e.g. "<h1 ...)" — a typo'd paren)
made GET /<slug>/ return 502, surfaced as a Cloudflare error page. Root
cause: the kernel `parse` raises a native Parse_error that an SX (guard ...)
cannot catch (guard only traps SX conditions), so host/blog-render's guard
around (parse sx) was ineffective; the exception escaped to the http-listen
loop, which swallowed it and wrote NO response — a dropped connection that
Caddy/Cloudflare relay as 502.

- kernel: add `parse-safe` — like parse but returns nil on malformed input
  (value-returning, so untrusted text can be handled without a host exception).
- kernel: http-listen now synthesises a 500 response on ANY handler exception
  instead of dropping the connection, so the origin stays responsive (no more
  proxy 502 / branded error page) and the error is logged. This is also the
  only place a native exception can be trapped, since SX guard can't.
- blog: host/blog-render uses (parse-safe sx) — malformed bodies render the
  existing "(unparseable content)" placeholder; the per-block render guard
  already covers unknown components (~kg-*), so /mddddd/ recovers too.

Verified live: /try-thus/ and /mddddd/ now 200 with placeholders; working
posts, home, and login unaffected. 193/193 conformance.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-25 22:08:33 +00:00
parent 3b8e1dfe2e
commit 83044ad2f0
2 changed files with 33 additions and 5 deletions

View File

@@ -76,7 +76,7 @@
(fn (record)
(let ((sx (get record :sx-content)))
(if (and sx (not (= sx "")))
(let ((tree (guard (e (true nil)) (parse sx))))
(let ((tree (parse-safe sx)))
(cond
((nil? tree) "<p><em>(unparseable content)</em></p>")
((and (= (type-of tree) "list") (> (len tree) 0)