You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
main is currently red on this job (the #764 merge run), and it has blocked three merges in the last day. Splitting it out of #739, where I first reported it — it is not any of that issue's four items.
The failure
db extension (postgres service) → Run full suite with live DATABASE_URL → tests/test_http_rss_growth.sh (suite [45c]):
and on another run, RSS2 alone at 1540 kB / 788 B per req. Not noise: the threshold is 64 kB and the observed growth is 20-40x it, measured between two steady-state checkpoints (the harness already excludes the ~1.4 MB one-time arena warmup).
Rate, and a bisection point
Last 20 CI runs, db extension only:
when (UTC)
branch
db job
07-28 06:25 … 21:51
main + 5 PRs
all pass (8 runs)
07-28 23:02
main 8aaf44a
FAIL
07-29 00:36, 00:55
fix/735
pass
07-29 01:32
main cdcb31e
FAIL
07-29 03:20, 03:40
fix/739-trace, main 52aa990
pass
07-29 05:20
fix/739-exit
pass
07-29 05:48
main c913ea9
FAIL
07-29 06:24
fix/739-task
FAIL
07-29 07:30
fix/739-globals
pass
07-29 07:49
main b70e649
FAIL
Every run before 07-28T23:02 is clean; 5 of the 12 runs since have failed. 07-28T23:02 UTC is the CI run for 8aaf44a — fix(json): bound json_encode depth (#730/#757) — whose local commit time is 07-28T18:02 CDT, the same instant. So the onset coincides exactly with that merge.
I want to be careful with that: it is a correlation with a clean before/after boundary, not a demonstrated mechanism, and #757's own PR run passed. Treat it as where to bisect first, not as the answer.
Why it is at least plausible: 8aaf44a changed eigs_json_encode to return NULL on refusal and touched both ext_http.c callers — shared_set and shared_incr — and RSS1 exercises shared_incr. That is the same call-site family that #731 found three ownership bugs in ("if you touch one, re-audit the rest"). Reading the diff I could not find the leak: the new early returns look correct and the encoder frees its strbuf on the failure path. So either it is subtler than a read reveals, or the correlation is coincidental.
Not visible in the http variant. Locally, make http (http+model, no db) runs the same gate clean: 0 kB over 2000 reqs on both checks, 5 consecutive runs.
Not catchable by any sanitizer. Per CLAUDE.md, LeakSanitizer runs atexit and the test server is killed with no SIGTERM handler, so LSan never runs in the server process. make asan-http is clean (3374/3374, leak tally 0) and would stay clean with this bug present. The RSS gate is the only instrument that sees this class — which is also why it must not be quietened.
Suggested next steps
The failing job conflates three variables that no other job combines: the full variant (http+model+db), a container, and a live postgres service. Separate them before touching code:
Full variant, container, no DATABASE_URL → isolates the live service.
http variant (no db) inside the same container → isolates db linkage from the environment.
Full variant on a plain runner → isolates the container.
If (2) fails, it is environmental and the code is fine. If (1) or (3) fails, bisect 8aaf44a directly: revert its ext_http.c hunk on a branch and run the db job a few times — the ~25% rate means a single green run proves nothing, so run it at least 5 times either way.
I could not do any of this here: this box has no libpq at all (no headers, no library), so the full variant cannot be built locally.
Meanwhile
Because the rate is ~25%, a red run on an unrelated PR is not evidence about that PR. Re-run the job; if it goes green the PR is fine. Do not merge past a reproducible red on this gate — a per-request leak in the HTTP server is exactly the class nothing else catches.
mainis currently red on this job (the #764 merge run), and it has blocked three merges in the last day. Splitting it out of #739, where I first reported it — it is not any of that issue's four items.The failure
db extension (postgres service)→ Run full suite with live DATABASE_URL →tests/test_http_rss_growth.sh(suite [45c]):and on another run, RSS2 alone at
1540 kB / 788 B per req. Not noise: the threshold is 64 kB and the observed growth is 20-40x it, measured between two steady-state checkpoints (the harness already excludes the ~1.4 MB one-time arena warmup).Rate, and a bisection point
Last 20 CI runs,
db extensiononly:8aaf44acdcb31e52aa990c913ea9b70e649Every run before 07-28T23:02 is clean; 5 of the 12 runs since have failed. 07-28T23:02 UTC is the CI run for
8aaf44a— fix(json): bound json_encode depth (#730/#757) — whose local commit time is 07-28T18:02 CDT, the same instant. So the onset coincides exactly with that merge.I want to be careful with that: it is a correlation with a clean before/after boundary, not a demonstrated mechanism, and #757's own PR run passed. Treat it as where to bisect first, not as the answer.
Why it is at least plausible:
8aaf44achangedeigs_json_encodeto return NULL on refusal and touched bothext_http.ccallers —shared_setandshared_incr— and RSS1 exercisesshared_incr. That is the same call-site family that #731 found three ownership bugs in ("if you touch one, re-audit the rest"). Reading the diff I could not find the leak: the new early returns look correct and the encoder frees itsstrbufon the failure path. So either it is subtler than a read reveals, or the correlation is coincidental.What is already ruled out
g_db_conn/ per-state db registration. I proposed this in Multi-state boundary: trace.c is entirely process-global and ext_http's per-connection worker calls trace_shutdown(), destroying the process tape on every request #739 and it is wrong:db_connectis only ever called explicitly (ext_db.c:63), and this test drivesshared_incrand an authed route — no connection is ever opened. The db builtins are registered per worker env, but as ordinarymake_builtinvalues freed with the env, exactly like the http/model ones that do not leak.make http(http+model, no db) runs the same gate clean:0 kB over 2000 reqson both checks, 5 consecutive runs.atexitand the test server is killed with no SIGTERM handler, so LSan never runs in the server process.make asan-httpis clean (3374/3374, leak tally 0) and would stay clean with this bug present. The RSS gate is the only instrument that sees this class — which is also why it must not be quietened.Suggested next steps
The failing job conflates three variables that no other job combines: the full variant (http+model+db), a container, and a live postgres service. Separate them before touching code:
DATABASE_URL→ isolates the live service.If (2) fails, it is environmental and the code is fine. If (1) or (3) fails, bisect
8aaf44adirectly: revert itsext_http.chunk on a branch and run the db job a few times — the ~25% rate means a single green run proves nothing, so run it at least 5 times either way.I could not do any of this here: this box has no libpq at all (no headers, no library), so the full variant cannot be built locally.
Meanwhile
Because the rate is ~25%, a red run on an unrelated PR is not evidence about that PR. Re-run the job; if it goes green the PR is fine. Do not merge past a reproducible red on this gate — a per-request leak in the HTTP server is exactly the class nothing else catches.