test(broker): harden acceptance socket-read against empty/truncated reply (flaky main #1917) #838
Reference in New Issue
Block a user
Delete Branch "%!s()"
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?
Broker acceptance harness reddens
mainunder load — root-caused to broker-side deadline exhaustion (flaky), not a test-only read race.Symptom
push/ci pipeline 1917 on
main(abd2791f, WI-2 squash)teststep failed with 3 uncaught exceptions, allSyntaxError: Unexpected end of JSON inputthrown inSocket.<anonymous>handlers:packages/mosaic/src/lease-broker/lease-broker.acceptance.spec.ts:69packages/mosaic/src/mutator-gate/mutator-gate.acceptance.spec.ts:54The identical tree passed 100% on pr/ci 1915. 1917 runs
testconcurrently withbuild+publish(heavy contention). Load-sensitive, not a guard-logic regression (1382/1385 pass; mutator-class regression matrix green).Root cause (broker-side, confirmed)
framework/tools/lease-broker/daemon.pyhandle_connection()uses a single connection deadlinedeadline = time.monotonic() + CONNECTION_DEADLINE_SECONDSspanning all of:read_frame->broker_lock/broker.handle(state mutation + fsync) ->sendall. The send block:Under contention the deadline can exhaust after
handle()mutated+fsync'd state but before the reply is sent, so the broker closes with no reply. The client then reads empty/truncated, and both specs duplicate arequest()helper that doessocket.once('end', () => resolve(JSON.parse(response)))—JSON.parse('')throws synchronously inside the'end'listener, after the Promise executor returned => uncaught exception, failing the file.Required repair
1 — Deterministic typed transport failure (test harness). Both
request()helpers must surface a typed transport failure (empty / truncated / early-close) — reject-with-context (responsebytes + length), no uncaught exception, and no silent tolerate/retry that turns red into green. A test that hits the empty-reply path must fail loud and deterministic, never pass by retrying until the broker happens to reply. Dedupe to one shared helper if clean.2 — Bounded broker deadline semantics (product-side). A completed
broker.handle()must always get its reply flushed. Do not let one shared deadline drop a reply after authority state was already mutated+fsync'd. Introduce separate/extended budgets for read vs handle vs send so a processed request is never answered with a silent close. State the security reasoning.3 — Real adapter fail-closed proof (Opus SECREV mandatory). PROVE (construct + run, not assume) that the real Claude/Pi lease adapter read-path FAIL-CLOSES on an empty/truncated reply: parse-error ->
GATE_UNAVAILABLE-> deny. If empty could ever be mis-parsed/defaulted -> ALLOW, that is HIGH (this is exactly WI-2's lifecycle/auth surface). Also assess the dropped-reply TOCTOU:handle()mutates+fsyncs authority (generation bump / revoke) but the client never learns the outcome when the reply is dropped -> divergent broker/client authority state.Integrity (load-bearing)
catch -> resolve({ok:false})is assertion-laundering — rejected).mainpush/ci must go genuine deterministic-green (verify, don't assume).--no-verify.Context