P1: Complete cancellation/disconnect propagation outside the established stream path (#165 successor) #225
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
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Creatidy/scarcity-router#225
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
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?
Goal
Priority: P1 (owner-declared 2026-10-27 backlog disposition, D-083). Complete client-disconnect/cancel propagation on the execution-stream paths outside the already-proven established-stream path. Active successor of excluded
wontfixissue #165; #165 stays open/excluded and unchanged.Why and Evidence
#165 recorded four production paths deferred from the PR #164 review. The 2026-10-27 reconciliation verified each against
develop4a182affa4775a4a38b47860ad7622a099c56c4a(no develop commit changed them since filing):worker_bridged_adapter.py_await_outcome()(~213-214) and_await_resume()(~452-454): whencancel_eventis set while blocked inpending.take()and a chunk then arrives, the branch returnsAdapterResult(status="cancelled")without_send_cancel_best_effort; the loop never reaches the next top-of-loop check. Latent under current coordinator wiring (todaycancel_eventis set only on the covered emit-raise/post-return paths) but a live adapter-contract hole (e.g. a future deadline timer).gateway_server.py_StreamState._begin()(~775-779):send_response/send_header/end_headerssit outside_write_frame()'sBrokenPipeError/ConnectionResetError/OSError → ClientDisconnectedErrortranslation (~827-835), so a header-write failure escapes as rawOSErrorthrough the generic unwind; coordinatorcancel_eventnever set._ResponsesStreamState._write_events(~919-923, added with #181 D-080 on 2026-10-25) replicates the untranslated header-emission pattern of path 2.worker_bridged_adapter.py_await_outcome()(~261-273) and_await_resume()(~487-502): suspension-branchcontext.emit_chunk(...)calls for tool-call/finish frames sit outside anyClientDisconnectedErrorcatch, unlike the ordinary chunk branch — disconnect during these emissions triggers no worker cancellation and leaves the backend turn suspended endpoint-side.Intentional contract to preserve (path 4 of #165): worker connection loss at submit →
AdapterAmbiguousError;interruptedoutcome →AdapterAmbiguousError;TOOL_RESULT_AMBIGUOUS→AdapterAmbiguousError. Honest ambiguity, never retry. Existing regression tests cover only the already-covered branches.Scope
Verify and deterministically reproduce each defect at current HEAD before any behavior change (red tests first, synthetic probes/seams only — no timeout/sleep-based correctness). Then make the minimal local fixes:
cancel_sentso cancellation effects are never duplicated);_begin()and_write_eventstoClientDisconnectedErrorso the existing coordinator cancellation path engages for Chat Completions and Responses;Non-goals: no execution-coordination redesign, no worker-protocol change, no automatic retry of ambiguous execution, no change to the ambiguous-outcome contract, no change to PR #164's merged test synchronization.
Acceptance Criteria
completed/cancelledoutcomes.uv sync --only-dev,make check,uv run basedpyright,git diff --check), deterministic offline tests only; fresh independent technical review (security assessment included) at exact frozen HEAD/base.Constraints
Keep the fix local to the identified paths. Preserve #143/PR #164 outcomes. No new public contract, protocol version, credential handling or network surface. Security-relevant correctness fix, not architecture.
Links
Excluded predecessor #165 (historical, unchanged); D-083 disposition; D-043 audit/ambiguity, D-062 continuation boundary, D-080 Responses ingress;
worker_bridged_adapter.py,gateway_server.py,gateway_coordinator.py.Completed/integrated via PR230 on 2026-10-28, merge04f40ddf59ea1abba6719208166daa94aeeddb1a on develop. Parents reviewed base2c40e0e1fb79397c97e6fa2b7dac0365d9712c0c and HEADebb5a4093feda19d4e73e0769ecf4b081596398c; merge-base4a182af. Fresh Git verified ancestry and integrated tree7b0416513ab3859277ffbcb98e517d2066ce1b07 EXACTLY equals full-gate-tested candidate. No implementation restart/history rewrite. Six deterministic original red/green regressions cover initial/resume chunk-cancel windows, initial/sequential suspension-emission disconnects, Chat/Responses SSE headers; existing real-socket midstream tests on both APIs remain green. Full sanitized integration-tree gate:uv sync --only-dev; make check3063 OK/18 skips(725.455s);basedpyright0/0/0;whitespace clean. Native independent GLM-5.3 pr-reviewer session ses_e7dae7b1cffe7M3L5csT38SQmR ordinal1/10:APPROVE/findings[], correctness+security+UX assessed, including clarified effect-idempotent cancellation and existing bounded-expiry cleanup of WAITING handles. No ambiguous-execution retry, continuation/protocol/security weakening or release action. Historical165 remains open/wontfix as required by D-083. Acceptance satisfied; closing225 and resuming canonical loop.