Test suite stabilization: root-cause the 502 flake, zero resource leaks, -33% runtime, timing observability #112
No reviewers
Labels
No labels
accessibility
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
P1
P2
P3
question
wontfix
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Creatidy/scarcity-router!112
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/test-suite-stabilization"
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?
Closes #111.
Root causes found (with evidence)
1. The intermittent
502 backend_failureinPackagedWorkerPathTests— a real product lifecycle bug.default_connect_factoryleftsocket.create_connection's 10 s timeout active for the whole worker session. With the server-advertised 15 s heartbeat cadence, read-silence gaps longer than 10 s are routine, so the worker's read loop hit the socket timeout, treated the healthy session as lost, and tore it down (server logs the session close; worker reconnects with backoff and re-probes). A dispatch landing in that flap window found no authenticated session for the resource →AdapterPermanentError→ 502. Reproduced under CPU saturation:SR-DIAG session close: connection errorserver-side and a silent worker (adapter never failed — proving the server-side flap);Fix: the established session socket gets
SESSION_IO_TIMEOUT_SECONDS = 60(protocol-sane ceiling, far above the heartbeat cadence);request_stop()now also closes the active transport so a blocked read unwinds deterministically. Validated: 40/40 packaged-test passes under full 12-core saturation (previously failing ~1 in 8–10 runs).2. Second, independent flake in the same test (~1/64 runs): pairing codes beginning with
-.secrets.token_urlsafecodes can start with-; argparse then treats the code as a flag (--code: expected one argument). Reproduced once under load. Fixed at issuance (leading-redrawn, unit-pinned) and the test passes--code=<code>. This also fixes the same defect for real administrators pairing real devices.3. ResourceWarnings (70 in the baseline full-gate log). Product:
probe_codex_versionandCodexSessionleft child stdout/stderr pipe handles unclosed (warnings firing insideworker_codex_adapter.py), stderr drainer unjoined. Tests:stop_worker_processnever drained/closed the worker's pipes, in-processCodexWorkernever closed captured TLS transports, unclosedhttp.clientconnections intest_gateway_server, oneopen(...).read(). All ownership made deterministic (verified viaPYTHONTRACEMALLOCattribution +-W always::ResourceWarningper-file runs).4. Timing pathology. The flap imposed a ~10 s constant on ~20 composed-worker E2E tests (baseline profile: 15–26 s each). Two further timeout-waiting tests fixed:
RemoteBridgeTestscleanup order (server_close before shutdown spun the serve thread; join(5) always burned its ceiling) and the startup-banner test consuming a 20 s subprocess timeout to read a banner that is flushed at startup.Results
make check(wall)Timing observability:
SR_TEST_TIMING=1 make test(and CI's check step) prints the fifteen slowest tests and total test wall time via the new ~70-linetools/test_runner.py— no new dependencies, no new make targets, no extra CI statuses.Scope discipline
One gate (
make check) unchanged; nomake acceptance, nomake release-check, no pytest, no retries, no timeout-bumping as a fix, no coverage removed (1895 tests before, 1896 after — one new unit test). No provider/routing behavior changed beyond the lifecycle bug the 502 proved.Validation
make checkexit 0 (1896 tests, 416.0 s) with 0 ResourceWarningsmake package-checkexit 0;make guardrailsexit 0 (40 tests);git diff --checkcleantoken_urlsafe codes can begin with '-' (1 in 64). Such a code passed on the command line is read by argparse as a flag ('argument --code: expected one argument'), breaking the documented pair invocation for the administrator pasting the code — reproduced as a 1-in-64 flake in the packaged-worker acceptance test. A leading '-' is now redrawn at issuance; mid-code '-' stays legal.Independent review verdict — APPROVE
Reviewer: fresh GLM-5.3-Flash (thinking=MAX), one pass, adversarial mandate of 13 points (issue #111 / PR #112). Reviewed commit
bfd55dc; findings 1+2 below were fixed later on the branch (42cceb2) and findings 3+4 in the remediation commit1620ce1.Key confirmations (all with file:line evidence in the review record):
create_connection(timeout=10)leaves the 10 s timeout on the established socket, and a parked recv across a >10 s quiet gap raisesTimeoutErrorat exactly 10.0 s; traced the full chain_read_loop→ reconnect backoff →session_for_resourceraisingworker_offline→_begin→AdapterPermanentError→ coordinatorbackend_failure/502. Cadence math verified: 15 s heartbeat gap > 10 s ceiling. Verdict: "HONEST" fix — the 60 s ceiling is a new protocol-sane bound (above the server's 45 s liveness kill), not the old timeout reused; no retries, no swallowed 502, assertion strengthened with worker-stderr evidence.DEFER findings and their disposition:
_serve()cleanup-order bug (5 s × every RemoteBridge test) — fixed in42cceb2(after the reviewed commit).42cceb2.next_executedirect path ignoring its timeout — fixed in1620ce1(newSocketTransport.set_timeout; scenario_12 15.8 s → 7.6 s).1620ce1(mockedtoken_urlsafe).request_stopclosing a transport during the microscopic connect→register window unwinds via the 60 s ceiling — bounded, accepted, no action.Gate on the final commit (
1620ce1):make checkexit 0 (1896 tests, 416.0 s), 0 ResourceWarnings, basedpyright 0/0/0, package-check exit 0, guardrails exit 0,git diff --checkclean, orphan census unchanged (0 new).