Repository navigation
Bound upstream SSE reader queue and define reader lifecycle #19
Copy link
Copy link
Closed
Labels
P1Priority 1: current iteration goalPriority 1: current iteration goalbugSomething isn't workingSomething isn't workingready-for-agentFully specified, ready for an AFK agentFully specified, ready for an AFK agenttier:heavyOrchestrator provider tier: heavyOrchestrator provider tier: heavywayfinder:taskWayfinder implementation taskWayfinder implementation task
Description
Outcome
Bound the upstream SSE reader lifecycle so slow or closed downstream clients cannot create unbounded buffering, stuck producers, or shutdown races.
Design and scope
- Use an upstream reader queue with exact capacity 32.
- Backpressure must be cancellable: a producer waiting on a full queue observes request/downstream/shutdown cancellation without an unbounded blocking
put. - Close the upstream response on EOF, timeout, downstream close, protocol error, handler exit, and Gateway shutdown. Wake both producer and consumer on every terminal path.
- Join the reader for at most 1 second and classify any non-termination without hiding it. Overall Gateway shutdown with these readers must complete within 2 seconds.
- Preserve keepalive, idle-timeout, successful stream ordering, and the 499 downstream-close behavior established by Handle downstream client disconnects consistently for all SSE writes #18. Do not add fallback or alter provider retry policy.
Deterministic acceptance
- Tests fill the 32-entry queue with a stalled consumer and prove bounded memory plus cancellable producer exit.
- Tests cover normal EOF, upstream error, idle timeout, downstream close, shutdown during full-queue backpressure, repeated close, join timeout, and no orphaned reader thread.
- Tests prove close is idempotent,
join <= 1s, Gatewayshutdown <= 2s, no deadlock, no duplicate terminal/completion, and stable keepalive/idle semantics. - The shared
src-python/codex_proxy.pyand routing/proxy shutdown tests remain serial with Handle downstream client disconnects consistently for all SSE writes #18 and Reassemble multi-line SSE data events before JSON parsing #20.
Final-SHA real-client gate
Every final candidate SHA must build Debug and pass the same twelve pinned-VM real-client cases:
- Desktop and CLI:
gpt-5.6-lunaandvolc/glm-5.2. - OpenCode, ZCode, Pi, and OMP: candidate-managed Luna selector and exact
codexhub-volc/glm-5.2. - Each case uses a disposable sentinel file, a real read-only tool call, and a streamed short sentinel; it proves canonical model, expected terminal, exactly one
request_complete=200, and no duplicate, fallback, or unclassified reconnect. - Desktop/ZCode are human GUI gates; login/credentials/GUI fail closed. Only one retry is allowed for pre-output capacity 429/503. A new SHA invalidates all evidence.
Issue-specific real-client evidence runs four CLI processes concurrently across Luna and Volc (two per route). All four must complete independently with bounded queue depth, canonical identity, one 200 completion each, and no starvation, fallback, duplicate, reconnect, stuck reader, or shutdown over two seconds.
Verification and integration
python -m pytest -q tests/test_routing.py tests/test_chat_completions_gateway.py tests/test_proxy_shutdown.py
python -m pytest -q
git diff --check
python scripts/report_quality_gates.pyThe quality-gate command is report-only. The final SHA also requires Debug build, GitHub Actions, a strict heavy Reviewer, and human VM evidence. Squash to dev only.
Hotset
src-python/codex_proxy.pytests/test_routing.pytests/test_chat_completions_gateway.pytests/test_proxy_shutdown.py
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
P1Priority 1: current iteration goalPriority 1: current iteration goalbugSomething isn't workingSomething isn't workingready-for-agentFully specified, ready for an AFK agentFully specified, ready for an AFK agenttier:heavyOrchestrator provider tier: heavyOrchestrator provider tier: heavywayfinder:taskWayfinder implementation taskWayfinder implementation task
Activity
NOirBRight commentedon Jul 9, 2026
Agent Brief
Category: bug
Summary: Bound upstream SSE reader buffering and make reader shutdown explicit.
Current behavior:
System.Collections.Hashtable.Current
Desired behavior:
System.Collections.Hashtable.Desired
Key interfaces:
Acceptance criteria:
Out of scope:
NOirBRight commentedon Jul 20, 2026
{ "contract": { "acceptance": [ "Queue capacity is exactly 32, observed depth never exceeds 32, and a producer blocked by a stalled consumer exits through cancellation without deadlock or unbounded memory growth.", "EOF, upstream error, idle timeout, downstream close, protocol error, handler exit, repeated close, and Gateway shutdown each close the upstream response and wake both sides exactly once.", "Reader join is at most one second, total Gateway shutdown is at most two seconds, a non-terminating reader is classified without being hidden, and no orphan reader remains in successful bounded paths.", "Downstream close retains exactly one sanitized request_complete=499 with no further write, retry, fallback, or duplicate terminal; normal and upstream-error paths also retain exactly one completion.", "Keepalive cadence, idle timeout, successful SSE ordering and bytes, transparent route identity, Chat terminal sequencing, and converted-route public behavior remain unchanged.", "A deterministic four-request concurrency regression across Official and third-party Responses/Chat routes proves independent bounded completion without starvation or shared cancellation.", "A static scope audit rejects unbounded reader queues, bare blocking producer puts, and production reader creation outside the lifecycle owner.", "No intermediate 12-case real-client run is performed; the final frozen 0.1.7 candidate consumes this behavior under Issue #227." ], "change_claims": { "paths": [ "src-python/codex_proxy.py", "tests/test_routing.py", "tests/test_chat_completions_gateway.py", "tests/test_proxy_shutdown.py" ], "resources": [ "gateway-upstream-reader-lifecycle", "gateway-sse-backpressure", "gateway-shutdown-cancellation" ] }, "dependencies": { "dispatch_after": [ 18, 223 ], "merge_after": [ 18, 223 ] }, "design": [ "Own every upstream SSE reader for one request through a single bounded lifecycle object around the existing stream relay; do not add a second SSE parser or change event semantics.", "Use an upstream queue with exact capacity 32. Producer backpressure must observe request, downstream-close, and Gateway-shutdown cancellation without an unbounded blocking put or unbounded buffering.", "Close the owned upstream response and wake producer and consumer on normal EOF, upstream error, idle timeout, downstream close, protocol error, handler exit, and Gateway shutdown. Close and wake operations are idempotent.", "Join the reader for at most one second and retain a sanitized classification when it does not terminate. The complete Gateway shutdown path with these readers remains bounded to two seconds.", "Preserve the request-scoped downstream commit and 499 accounting established by #223, successful stream bytes and order, keepalive and idle behavior, transparent route identity, and current retry/fallback policy.", "Keep protocol event assembly and converted-stream parsing outside this Issue; #224 and #225 own those boundaries. Use deterministic thread/lifecycle fixtures rather than intermediate real-client qualification." ], "difficulty": "heavy", "done_when": [ "Focused queue, cancellation, close, join, shutdown, and scope-audit regressions are observed failing before implementation and passing afterward.", "python -m pytest -q tests/test_routing.py tests/test_chat_completions_gateway.py tests/test_proxy_shutdown.py", "python -m pytest -q tests/test_protocol_translation.py (evidence-only unless the admission is explicitly amended)", "python -m pytest -q", "git diff --check", "python scripts/report_quality_gates.py (report-only)", "Exact-local-SHA Standards and Spec reviews report no blocker before the branch is pushed once.", "After local freeze, exactly one push/PR update and exact-SHA GitHub Actions run pass; real-client qualification remains deferred to the final 0.1.7 candidate." ], "priority": "P1", "risk": "strict", "sha256": "1cf75e684ea9f177b65b3765647adbd61e86d853d428e24933d88d7bd43b4db4", "unresolved_decisions": [] }, "dispatch": { "attempt": 2, "base_sha": "f00373f7cf28ab5288691b1aebfc696ec187e9c9", "branch": "work/issue-19", "claimed_at": "2026-07-26T00:05:33.000710Z", "contract_sha256": "1cf75e684ea9f177b65b3765647adbd61e86d853d428e24933d88d7bd43b4db4", "creator_agent_id": "d81c5928-aff7-4d9d-b6a0-2b9f70ffad21", "id": "dispatch-issue-19-a2", "recovery_prompt_sent": false, "status": "running", "worker_agent_id": "38ba4432-7041-4e5a-805a-164be94db431", "workspace_id": "wks_396a76df1991b322" } }NOirBRight commentedon Jul 25, 2026
Coordinator frontier correction (2026-07-25):
devbase and the approved local-first workflow.NOirBRight commentedon Jul 26, 2026
Completed by PR #232 and merged into
dev.f03d5df14d9abc788ed1840074e1d43cb74a53b47ba14f6fee6c21831f6ba7edf63b01b6ec0ba955