Fix truncated /api/safety-contact response (988 crisis-line) #96
Reference in New Issue
Block a user
Delete Branch "fix/safety-contact-truncation"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
POST/GET /api/safety-contact returned JSON truncated to the file's byte length. Root cause: el runtime response writer uses fs_read's thread-local _tl_fs_read_len as the send length (el_runtime.c:1409); both handlers fs_read then return a longer string. Soul-source fix: POST checks fs_write return (no fs_read); GET resets the thread-local with a no-op fs_read after the file read. Verified: full valid JSON, GATE PASS (both sections), genesis survives, floor compiled in. Stacks on #95 (genesis fix). Do NOT merge — mechanics agent rebuilds from HEAD. Ship-soul: see commit.
Saving the 988 crisis-line contact returned truncated, unparseable JSON — cut mid-"set_at" at the file's byte length (e.g. 178 of a 218-byte response). The contact written to disk was complete; only the HTTP response was clipped, so a real customer's crisis-contact save came back corrupt. Root cause is in the el runtime's response writer, not a handler buffer: fs_read stores the file's byte count in a thread-local (_tl_fs_read_len) for binary-safe file serving, and the response writer uses that length when non-zero instead of strlen(body) (el_runtime.c:1409). Both safety-contact handlers call fs_read (the POST read-back verify; the GET file read) and then return a LONGER wrapped JSON string, so the response is capped to the file size. Soul-source fix (no runtime change needed): - POST: verify persistence via fs_write's return (1 = all bytes written) instead of an fs_read read-back — removes the fs_read, so nothing caps the response. - GET: fs_read is required, so reset the thread-local after it with a no-op fs_read("") (fs_read zeroes the length before it opens a path) so the wrapped response is sent in full. Verified: POST (crisis-line + custom) and GET now return complete, valid JSON (parses cleanly, full contact incl. set_at). Regenerated dist/soul.c + dist/safety.c (3GB RSS watchdog, release el_runtime v1.0.0-20260501). Full suite still green: verify-soul-contract GATE PASS (PRESENCE + IMMUTABILITY), genesis boot survives (/health 200, no segfault), bounded- persona floor still compiled in. NOTE: the underlying runtime leak (any handler that fs_reads then returns a longer string) is worth a proper fix in el_runtime.c (use the max of strlen and _tl_fs_read_len) so this class can't recur.