Skip to content

Bound upstream SSE reader queue and define reader lifecycle #19

Closed

Description

@NOirBRight

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

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-luna and volc/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.py

The 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.py
  • tests/test_routing.py
  • tests/test_chat_completions_gateway.py
  • tests/test_proxy_shutdown.py

Activity

  1. added
    needs-triageMaintainer needs to evaluate this issue
    bugSomething isn't working
    ready-for-agentFully specified, ready for an AFK agent
    and removed
    needs-triageMaintainer needs to evaluate this issue
    on Jul 9, 2026
  2. NOirBRight commented on Jul 9, 2026

    @NOirBRight
    OwnerAuthor

    This was generated by AI during triage.

    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:

    • Upstream SSE line iterator
    • Idle/keepalive timeout behavior
    • Response close lifecycle

    Acceptance criteria:

    • Reader queue size is bounded.
    • Shutdown behavior is deterministic and tested for normal EOF, timeout, and downstream disconnect.
    • Existing keepalive and idle timeout semantics remain stable.

    Out of scope:

    • Do not claim or fix unrelated fd leaks without reproduction.
    • Do not alter retry policy.
  3. added
    P1Priority 1: current iteration goal
    tier:heavyOrchestrator provider tier: heavy
    on Jul 20, 2026
  4. NOirBRight commented on Jul 20, 2026

    @NOirBRight
    OwnerAuthor
    {
      "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"
      }
    }
  5. added
    orch:readyOrchestrator V6: valid hashed contract is complete and dispatchable
    on Jul 20, 2026
  6. added
    orch:blockedOrchestrator V6: blocked pending a decision or external state change
    and removed
    orch:readyOrchestrator V6: valid hashed contract is complete and dispatchable
    on Jul 25, 2026
  7. NOirBRight commented on Jul 25, 2026

    @NOirBRight
    OwnerAuthor

    Coordinator frontier correction (2026-07-25):

  8. added
    orch:readyOrchestrator V6: valid hashed contract is complete and dispatchable
    orch:activeOrchestrator V6: claimed Worker is active or rework is in progress
    and removed
    orch:blockedOrchestrator V6: blocked pending a decision or external state change
    orch:readyOrchestrator V6: valid hashed contract is complete and dispatchable
    on Jul 25, 2026
  9. NOirBRight commented on Jul 26, 2026

    @NOirBRight
    OwnerAuthor

    Completed by PR #232 and merged into dev.

    • Candidate: f03d5df14d9abc788ed1840074e1d43cb74a53b4
    • Squash merge: 7ba14f6fee6c21831f6ba7edf63b01b6ec0ba955
    • Exact-SHA CI run 30182409451: 7/7 successful
    • Native combined/heavy review: pass, findings empty
    • Local verification used the explicit affected matrix; superseded repo-wide attempts were not treated as failures, and real-client qualification remains owned by Freeze and qualify the 0.1.7 dev release candidate #227.
  10. removed
    orch:activeOrchestrator V6: claimed Worker is active or rework is in progress
    on Jul 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1Priority 1: current iteration goalbugSomething isn't workingready-for-agentFully specified, ready for an AFK agenttier:heavyOrchestrator provider tier: heavywayfinder:taskWayfinder implementation task

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions