Skip to content

Reassemble multi-line SSE data events before JSON parsing #20

Closed

Description

@NOirBRight

Outcome

Parse protocol-valid SSE events at event boundaries, preserving multiline data and metadata without changing transparent byte identity or turning semantic JSON errors into malformed downstream streams.

Design and scope

  • Add one blank-line-delimited SSE assembler wherever the Gateway semantically parses upstream SSE.
  • Join repeated data: fields with a literal newline before JSON or [DONE] handling, per SSE semantics.
  • Preserve event metadata (event, id, retry, comments, unknown fields/order where represented) and retain the raw event bytes for routes that require transparent forwarding or sanitized diagnostics.
  • Transparent routes must forward byte-identical input, including CRLF/LF choice and raw bytes; parsing must not normalize or reserialize them.
  • Converted Responses↔Chat routes consume assembled semantic events, preserve representable metadata and ordering, and handle [DONE] exactly once.
  • A protocol-valid SSE event whose assembled data is semantically invalid JSON returns a protocol-valid sanitized 502 with no payload echo, no partial success terminal, no retry/fallback after exposure, and exactly one completion record.

Deterministic acceptance

  • Fixtures cover multi-line JSON, newline-bearing data, [DONE], metadata/comments, blank lines, CRLF/LF, fragmented input, unknown fields, invalid UTF-8/raw bytes on transparent paths, and semantic invalid JSON.
  • Deterministic Responses→Chat and Chat→Responses tests prove multiline assembly, metadata/raw preservation, transparent byte identity, single terminal, and sanitized 502 behavior.
  • Existing single-line events and successful transparent streams remain unchanged.
  • The shared src-python/codex_proxy.py and routing/protocol tests remain serial with Handle downstream client disconnects consistently for all SSE writes #18 and Bound upstream SSE reader queue and define reader lifecycle #19.

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 evidence includes deterministic Responses↔Chat multiline, [DONE], metadata, invalid-JSON, and raw-byte cases on the final SHA. Converted invalid JSON must end as one sanitized protocol-valid 502; transparent cases must remain byte-identical.

Verification and integration

python -m pytest -q tests/test_routing.py tests/test_chat_completions_gateway.py tests/test_protocol_translation.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
  • src-python/protocol_translation.py
  • tests/test_routing.py
  • tests/test_chat_completions_gateway.py
  • tests/test_protocol_translation.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: Parse multi-line SSE data events as one event.

    Current behavior:
    System.Collections.Hashtable.Current

    Desired behavior:
    System.Collections.Hashtable.Desired

    Key interfaces:

    • SSE event parser
    • Responses/Chat stream event conversion
    • Telemetry for parse failures

    Acceptance criteria:

    • Multi-line data events parse as a single payload.
    • Single-line events and [DONE] behavior are unchanged.
    • Tests cover multi-line JSON and parse failure telemetry without sensitive payload logging.

    Out of scope:

    • Do not refactor all protocol conversion in this issue.
    • Do not change transparent byte-forwarding semantics.
  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
    ```json { "contract": { "acceptance": [ "One production SSE assembler handles LF, CRLF, CR, split boundaries, repeated data, comments, metadata, unknown fields, BOM, empty frames, arbitrary fragmentation, incomplete EOF, invalid raw bytes, and the bounded frame limit.", "Every converted production stream consumes complete assembler frames and no line-oriented or arbitrary-chunk JSON parser remains.", "Responses-to-Chat and Chat-to-Responses preserve ordered text, representable reasoning, tool IDs/names/arguments/results, usage, canonical model identity, and one target-protocol terminal sequence.", "Transparent routes remain byte-identical for line endings, metadata, unknown fields, and invalid UTF-8, and do not enter semantic conversion.", "Malformed complete converted events emit one sanitized target-protocol failure and exactly one request_complete=502 with no payload echo, retry, fallback, duplicate terminal, or later success.", "The exact #224 then #225 local gates, strict reviews, single pushes, exact-SHA CI runs, and serial dev merges are durable before #20 closes.", "No intermediate 12-case real-client run is performed; #227 validates the integrated behavior on the frozen release candidate." ], "change_claims": { "paths": [], "resources": [ "issue-20-parent-acceptance", "gateway-sse-event-assembler", "gateway-converted-sse" ] }, "dependencies": { "dispatch_after": [ 224, 225 ], "merge_after": [ 224, 225 ] }, "design": [ "Treat #20 as the parent acceptance and closure record for the serial #224 assembler and #225 converted-stream migration. Do not dispatch a third implementation Worker or add another SSE parser.", "Consume #224's pure lossless event-boundary assembler and #225's migration of every converted Responses-to-Chat and Chat-to-Responses stream. Event framing remains in sse_events.py and protocol semantics remain in protocol_translation.py.", "Transparent Passthrough forwards exact original bytes without semantic reserialization. Converted routes parse JSON only from complete assembled data values, join repeated data fields with a literal newline, and recognize protocol terminals only at complete event boundaries.", "Malformed complete converted events use the request-scoped terminal seam for one sanitized target-protocol failure and one 502 completion. Incomplete EOF never becomes a semantic event; no payload echo, retry, fallback, duplicate terminal, or later success is allowed.", "Close #20 only after both children are integrated serially into dev and their exact reviews/CI are durable. Do not run the 12-case matrix on either child or parent; #227 performs the sole final real-client qualification." ], "difficulty": "heavy", "done_when": [ "Issue #224 is merged to dev and Issue #225 is then rebased from that dev head, locally qualified, reviewed, pushed once, CI-green, and merged.", "The merged dev tree and child deliveries prove every #20 acceptance item through deterministic tests and static parser audit.", "A parent closure comment records both merged SHAs/PRs/reviews/CI evidence and the final-E2E deferral to #227.", "Issue #20 is closed without another Worker, PR, candidate SHA, or intermediate real-client matrix." ], "priority": "P1", "risk": "strict", "sha256": "531da939fb2b6188cadb1a734fca29290eb76855b2802e7704c354f79cd17fa9", "unresolved_decisions": [] }, "dispatch": null } ```
  5. added
    orch:readyOrchestrator V6: valid hashed contract is complete and dispatchable
    on Jul 20, 2026
  6. 1 remaining item

  7. added
    orch:blockedOrchestrator V6: blocked pending a decision or external state change
    and removed
    orch:readyOrchestrator V6: valid hashed contract is complete and dispatchable
    ready-for-agentFully specified, ready for an AFK agent
    orch:blockedOrchestrator V6: blocked pending a decision or external state change
    on Jul 25, 2026
  8. NOirBRight commented on Jul 25, 2026

    @NOirBRight
    OwnerAuthor

    Phase 0 decomposition / frontier correction (2026-07-25):

  9. added
    orch:readyOrchestrator V6: valid hashed contract is complete and dispatchable
    and removed
    orch:blockedOrchestrator V6: blocked pending a decision or external state change
    on Jul 25, 2026
  10. NOirBRight commented on Jul 26, 2026

    @NOirBRight
    OwnerAuthor

    Parent acceptance closure — satisfied by #224 → #225

    No third implementation Worker or candidate was created for #20, as required by its V2 contract.

    Durable child evidence:

    Together these deliveries implement the one lossless event-boundary assembler and migrate converted Responses↔Chat streams to complete-frame parsing while preserving transparent byte identity, multiline data: semantics, sanitized protocol-valid failures, and exactly-once terminal accounting. Both child Issues are closed.

    Per the contract, no intermediate 12-case real-client run was performed for #20. The integrated final-SHA behavior remains part of the sole authoritative release qualification in #227.

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 workingorch:readyOrchestrator V6: valid hashed contract is complete and dispatchableready-for-humanRequires human implementationtier:heavyOrchestrator provider tier: heavywayfinder:taskWayfinder implementation task

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions