runtime: durable fix for HTTP response truncation (both runtimes) — unblocks Windows brain #79

Closed
will.anderson wants to merge 0 commits from fix/durable-response-truncation into main
Owner

Root cause: the fs_read binary-length hint (_tl_fs_read_len) was applied to ANY HTTP body, so any handler that read a file then wrapped it into a larger reply had the response truncated to the file's length — Content-Length lied and the send stopped short. This is the Mac 988 safety-contact bug AND the Windows 'every answer cut off, app refuses the new user' bug (the Windows brain is an old build without even the per-handler workaround, so everything truncates).

Durable fix (pointer-identity, same approach as #78 by Tim, extended): pair the length hint with the exact buffer pointer it describes (_tl_fs_read_buf); apply the raw byte count ONLY when the response IS that buffer. Every wrapped/derived body uses strlen. Also closes the stale-hint heap over-read that a plain max() would leave open.

Key difference from #78: applied to BOTH the mainline runtime AND the frozen release runtime (lang/releases/v1.0.0-20260501) that the desktop souls compile against. #78 only touched mainline and is 21 commits behind main; the release copy still carried the raw leak — the reason the Windows brain kept truncating. This branch is rebased onto current main and supersedes #78.

Verification: both runtimes gcc -fsyntax-only clean. E2E no-truncation evidence produced via the Windows brain rebuild gate (988 POST+GET full untruncated JSON).

Closes the truncation class on every platform. Does not force a Mac rebuild — the in-flight Mac DMG keeps working via its existing workaround and can drop it later.

Root cause: the fs_read binary-length hint (`_tl_fs_read_len`) was applied to ANY HTTP body, so any handler that read a file then wrapped it into a larger reply had the response truncated to the file's length — Content-Length lied and the send stopped short. This is the Mac 988 safety-contact bug AND the Windows 'every answer cut off, app refuses the new user' bug (the Windows brain is an old build without even the per-handler workaround, so everything truncates). Durable fix (pointer-identity, same approach as #78 by Tim, extended): pair the length hint with the exact buffer pointer it describes (`_tl_fs_read_buf`); apply the raw byte count ONLY when the response IS that buffer. Every wrapped/derived body uses strlen. Also closes the stale-hint heap over-read that a plain max() would leave open. Key difference from #78: applied to BOTH the mainline runtime AND the frozen release runtime (`lang/releases/v1.0.0-20260501`) that the desktop souls compile against. #78 only touched mainline and is 21 commits behind main; the release copy still carried the raw leak — the reason the Windows brain kept truncating. This branch is rebased onto current main and supersedes #78. Verification: both runtimes `gcc -fsyntax-only` clean. E2E no-truncation evidence produced via the Windows brain rebuild gate (988 POST+GET full untruncated JSON). Closes the truncation class on every platform. Does not force a Mac rebuild — the in-flight Mac DMG keeps working via its existing workaround and can drop it later.
will.anderson added 1 commit 2026-07-22 20:04:52 +00:00
The binary-safe fs_read length (_tl_fs_read_len) was consumed by the HTTP
response path for ANY body, even when a handler wrapped a smaller file into a
larger reply. Content-Length then lied AND the send stopped short: the
safety-contact (988) routes returned 178 of 208/218 bytes, cut mid-'set_at' —
unparseable JSON. The desktop app read that as failure. On Windows the shipped
brain is an OLD build without even the per-handler workaround, so EVERY reply
truncated: the app can't read confirmations and refuses the new user.

Durable fix: pair the length hint with the exact buffer pointer it describes
(_tl_fs_read_buf). Apply the raw byte count ONLY when the response IS that
buffer (binary file serving stays correct); every wrapped/enveloped/derived
body is measured with strlen. Reset both at request start and in fs_read /
json_get_raw. This also closes the stale-hint heap over-read (a length larger
than a later body would read past it out the socket) that a plain max() leaves
open — so this class of bug dies on every platform, not just where a handler
happened to be patched.

Applied identically to the mainline runtime (lang/el-compiler/runtime) AND the
frozen release runtime (lang/releases/v1.0.0-20260501) the desktop souls
compile against — the release copy still carried the raw leak, which is why the
Windows brain kept truncating. Same proven approach as PR #78 (Tim Lingo),
extended to cover the release runtime and rebased onto current main.

Both runtimes: gcc -fsyntax-only clean.
Author
Owner

Measured no-truncation evidence (release runtime, lang/releases/v1.0.0-20260501 — the runtime desktop souls compile against). Harness reproduces the bug pattern: handler fs_read()s a 10-byte file, then wraps it into a 160-byte 988-safety-contact JSON reply; response captured off a socketpair.

BEFORE (origin/main, raw leak):
Content-Length header : 10
Actual body bytes sent: 10
Expected (full) reply : 160
RESULT: FAIL — reply truncated to file length; body cut at '{"ok":true'

AFTER (this branch):
Content-Length header : 160
Actual body bytes sent: 160
Expected (full) reply : 160
RESULT: PASS — full untruncated reply; complete valid JSON

Both runtimes gcc -fsyntax-only clean. Binary file-serving path preserved by the eff_body == _tl_fs_read_buf pairing (same approach Tim E2E-verified in #78).

Measured no-truncation evidence (release runtime, lang/releases/v1.0.0-20260501 — the runtime desktop souls compile against). Harness reproduces the bug pattern: handler fs_read()s a 10-byte file, then wraps it into a 160-byte 988-safety-contact JSON reply; response captured off a socketpair. BEFORE (origin/main, raw leak): Content-Length header : 10 Actual body bytes sent: 10 Expected (full) reply : 160 RESULT: FAIL — reply truncated to file length; body cut at '{"ok":true' AFTER (this branch): Content-Length header : 160 Actual body bytes sent: 160 Expected (full) reply : 160 RESULT: PASS — full untruncated reply; complete valid JSON Both runtimes gcc -fsyntax-only clean. Binary file-serving path preserved by the eff_body == _tl_fs_read_buf pairing (same approach Tim E2E-verified in #78).
Author
Owner

Superseded by the reconciled el-cluster landing (feature #80 -> dev -> stage #81 -> main #82). Its content is included in that reconciled runtime now on the dev->stage->main chain. Closing to drive el open PRs to zero.

Superseded by the reconciled el-cluster landing (feature #80 -> dev -> stage #81 -> main #82). Its content is included in that reconciled runtime now on the dev->stage->main chain. Closing to drive el open PRs to zero.
will.anderson closed this pull request 2026-07-22 21:21:45 +00:00

Pull request closed

Please reopen this pull request to perform a merge.
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: neuron-technologies/el#79