Skip to content

fix(responses): recover encrypted output rejections without masking failures - #3753

Merged
lidge-jun merged 14 commits into
devfrom
codex/release-244-opaque-recovery-07c0
Sep 6, 2026
Merged

fix(responses): recover encrypted output rejections without masking failures#3753
lidge-jun merged 14 commits into
devfrom
codex/release-244-opaque-recovery-07c0

Conversation

@lidge-jun

@lidge-jun lidge-jun commented Sep 6, 2026

Copy link
Copy Markdown
Owner

Summary

Co-authored-by: yxr1995-maker 257504378+yxr1995-maker@users.noreply.github.com

Verification

  • Current head cd6d4d3 includes the final merge-review repairs: native preflight read resets reach the normal relay, caller abort is cleaned up before retry, and tee/eager EOF failures agree on account health and usage markers. Exact-head hosted CI34020474748 passed (Linux four shards, macOS two shards, gates and npm installation). Fresh independent review passed and both merge-review threads are resolved. The cascaded combo head e1f5a5b also passed full CI34020475627.
  • Regression coverage includes request-level one-shot recovery, repeated flat/nested errors in both relay modes, original raw-object identity, default preflight byte preservation, commitment barriers, missing-header parity and bounded synthesized-message redaction.
  • Added reset/abort, errored-reader preservation, account-avoidance, real-terminal/cancel precedence and streamAborted parity regressions. No local test suite, typecheck or build was run. No live Kiro request was made.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults.

The repository owner authorized admin integration without a second approval; CI, security review and current review findings were verified separately.

@coderabbitai

coderabbitai Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Team

Run ID: 8434a3d3-914f-4ede-bba1-4734186d1a48

📥 Commits

Reviewing files that changed from the base of the PR and between adb6961 and b73809f.

📒 Files selected for processing (13)
  • devlog/_plan/260906_release_244_followups/040_opaque_recovery.md
  • devlog/_plan/260906_release_244_followups/041_opaque_recovery_implementation.md
  • docs-site/src/content/docs/guides/sub-agent-surface.md
  • src/lib/errors.ts
  • src/server/relay-eager.ts
  • src/server/relay.ts
  • src/server/responses/combo-stream-preflight.ts
  • src/server/responses/core.ts
  • structure/04_transports-and-sidecars.md
  • tests/responses/passthrough-abort.test.ts
  • tests/responses/responses-opaque-blob-recovery.test.ts
  • tests/responses/sse-failed-tail.test.ts
  • tests/routing/combo-stream-preflight.test.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

Native Responses passthrough now recovers from specific encrypted function-output failures. Streaming preflight supports explicit retry predicates and missing content types. Tee and eager relays preserve upstream errors in bounded, redacted response.failed tails.

Changes

Opaque recovery and relay terminal handling

Layer / File(s) Summary
Preflight and error contracts
src/lib/errors.ts, src/server/responses/combo-stream-preflight.ts, src/server/responses/core.ts, tests/routing/combo-stream-preflight.test.ts
Flat SSE errors now expose their messages. Preflight accepts an injected retry predicate and optional missing content types. Encrypted function-output and agent_message content are recognized for recovery.
Encrypted-output recovery
src/server/responses/core.ts, tests/responses/responses-opaque-blob-recovery.test.ts, docs-site/src/content/docs/guides/sub-agent-surface.md, structure/04-transports-and-sidecars.md
Matching encrypted-output rejections can trigger one sanitized rebuild. Encrypted parts become [encrypted content omitted]. Tests cover JSON, streamed, eager, repeated-failure, and content-type cases.
Relay failed-tail synthesis
src/server/relay.ts, src/server/relay-eager.ts, src/server/responses/core.ts, tests/responses/sse-failed-tail.test.ts, tests/responses/passthrough-abort.test.ts
Relays capture redacted upstream errors and synthesize bounded response.failed frames at terminal-less EOF. Existing terminals remain unchanged.
Planning and implementation evidence
devlog/_plan/260906_release_244_followups/040_opaque_recovery.md, devlog/_plan/260906_release_244_followups/041_opaque_recovery_implementation.md
The planning records define retry predicates, headerless streaming behavior, relay bounds, regression coverage, and hosted-CI evidence.

Estimated code review effort: 4 (Complex) | ~60 minutes

Merge Risk: ⚪ Minimal · up to b7380

No actionable merge-blocking risk is established for the recovery and failed-tail changes.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant ResponsesPassthrough
  participant UpstreamResponses
  participant OpaqueBlobRecovery
  participant ResponsesRelay
  Client->>ResponsesPassthrough: send Responses request
  ResponsesPassthrough->>UpstreamResponses: forward request
  UpstreamResponses->>ResponsesPassthrough: return encrypted-output rejection
  ResponsesPassthrough->>OpaqueBlobRecovery: sanitize encrypted parts
  OpaqueBlobRecovery->>UpstreamResponses: retry request once
  UpstreamResponses->>ResponsesRelay: return streamed output or error
  ResponsesRelay->>Client: emit response.failed or existing terminal
Loading

Suggested reviewers: invalid-email-address

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 32 functions across 9 files. (4 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: encrypted output rejection recovery while preserving upstream failures. It is specific, concise, and aligned with the pull request objectives.
Full details: Docstring Coverage

Explanation

Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 32 functions across 9 files. (4 skipped: 4 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/release-244-opaque-recovery-07c0

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the bug Something isn't working label Sep 6, 2026
@lidge-jun
lidge-jun marked this pull request as ready for review September 6, 2026 07:29
@lidge-jun
lidge-jun requested a review from Ingwannu as a code owner September 6, 2026 07:29
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 6, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-06T08:13:11.606982Z cd6d4d3 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b73809f7e9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/server/responses/core.ts
Comment thread src/server/relay.ts
@lidge-jun

Copy link
Copy Markdown
Owner Author

리뷰 · 우선순위 75 / 80

이 PR은 release-244 플랜의 다음 칸 040_opaque_recovery입니다. 지금 dev HEAD adb696197(패키지 2.44.0, #3751 docs tidy까지 머지됨) 위에서, 암호화된 function/custom output이나 agent_message 안의 encrypted content가 업스트림에 거절될 때 한 번만 내용을 지우고(sanitize) 다시 보내며, 같은 거절이 반복되면 tee/eager 릴레이가 adapter_eof 대신 실제 업스트림 메시지response.failed를 남기게 합니다. 원본 이슈/PR은 #3535이고, Co-authored-by에 yxr1995-maker가 있습니다. 베이스는 dev, 브랜치 codex/release-244-opaque-recovery-07c0이며 draft입니다. 본문이 말하는 머지 순서는 이 레이어 → #3754 combo → Grok terminal입니다.

지금 HEAD의 src/server/responses/core.ts를 보면 outboundResponsesBodyCarriesOpaqueBlobOPAQUE_RESPONSES_INPUT_TYPES + top-level encrypted_content만 보고, shouldAttemptOpaqueBlobRecovery4xx만 받습니다. prepareOpaqueBlobRecovery_stripReasoningEncryptedContent만 켭니다. 스트림이 끝나기 전에 flat type: error로 암호화 거절이 오면, 클라이언트 쪽에서는 종종 incomplete/adapter_eof처럼 보입니다. 이 PR은 (1) function_call_output / custom_tool_call_output / agent_message 안의 encrypted_content part까지 opaque로 보고, (2) 그 정확한 거절 문자열(ENCRYPTED_FUNCTION_OUTPUT_REJECTION)일 때만 502도 허용하며, (3) 스트림 경로에서는 preflightComboStreamResponse좁은 retryable 판별자와 allowMissingContentType(native streaming이고 Content-Type이 비었을 때만)을 넘기고, (4) prepareOpaqueBlobRecovery_rawBody.input같은 객체 정체성으로 남긴 채 part를 [encrypted content omitted]으로 바꿉니다. 기본 combo preflight 호출자 시그니처(두 인자)는 그대로라서 다른 경로의 바이트 계약은 안 바뀝니다.

릴레이 쪽은 src/server/relay.tscreateSseTerminalOutputBoundary가 클라이언트에 나가는 프레임을 직접 읽으며 flat error 메시지를 기억하고, EOF 때 upstreamErrorTailFrame으로 response.failed를 씁니다. relay-eager.tsrelaySseWithFailedTail도 같은 upstreamError를 받습니다. failedTailFrame은 프레임 안에 [DONE]을 넣고, upstreamErrorTailFrame은 넣지 않은 뒤 호출부가 doneFrame을 따로 enqueue합니다. 테스트(sse-failed-tail, opaque recovery, combo-stream-preflight, passthrough-abort 일부)가 tee/eager, 기존 terminal 우선, DONE 한 번, raw-object 정체성, 기본 preflight 보존을 덮습니다. exact-head CI(리눅스 4샤드·macOS 2·gates)는 초록으로 보입니다. 로컬 스위트/타입체크/빌드와 라이브 Kiro는 본문대로 안 돌렸고, 트레인 non-goal과 맞습니다. types/config 대분할·중복 close와 무관합니다.

우선순위 75인 이유다. kiro-results(#3750)·docs tidy(#3751) 다음 필수 런타임 칸이고, #3754와 Grok terminal이 이 기반 위에 올라갑니다. 범위가 responses opaque 회복 + terminal 증거 보존에 묶여 있고, 기본 combo preflight를 넓히지 않은 점이 안전합니다. 남은 리스크는 draft 게이트, 원본 #3535 leftover, 그리고 _rawBody 현장 변형이 persistence WeakSet 계약과 계속 맞는지(본문·테스트가 주장)입니다.

경로/심볼 - src/lib/errors.ts ENCRYPTED_FUNCTION_OUTPUT_REJECTION / flat type==="error" 메시지 추출
경로/심볼 - src/server/responses/core.ts function/agent_message opaque 감지, 502 예외, streamed preflight 회복, prepareOpaqueBlobRecovery rawBody 변형
경로/심볼 - src/server/responses/combo-stream-preflight.ts optional retryableTerminal + allowMissingContentType
경로/심볼 - src/server/relay.ts / relay-eager.ts upstreamErrorTailFrame · reader 소유 terminal 증거
경로 - tests/responses/responses-opaque-blob-recovery.test.ts 등 회귀 매트릭스
경로/심볼 - 원본 #3535(draft, dev 직행 leftover) / 자식 #3754 / plan 040_opaque_recovery.md

메인테이너의 판단이 필요한 지점

  • draft를 Ready로 올리고 exact-head CI만 보고 머지할지(권장)
  • 머지 후 원본 #3535Landed via #3753 + landed-via-maintainer로 닫을지
  • upstreamErrorTailFrame이 DONE을 호출부에 맡기는 비대칭을 그대로 둘지(테스트상 문제 없음)
  • #3754를 같은 스택으로 바로 이어서 올릴지, opaque만 먼저 안정화할지

너의 추천
Ready 전환 후 exact-head CI 초록이면 dev에 머지하세요. release-244의 opaque 칸이고 #3754의 바닥입니다. 라이브 Kiro는 돌리지 마세요. types/config close-don't-rebase 아님. 머지 직후 #3535 leftover를 landed 처리하세요. 그다음 combo-recovery(#3754)로 넘어가세요.

이 댓글은 grok-bot이 작성했습니다

@lidge-jun
lidge-jun marked this pull request as ready for review September 6, 2026 08:08
@lidge-jun
lidge-jun merged commit b9f2acc into dev Sep 6, 2026
32 of 35 checks passed
@lidge-jun
lidge-jun deleted the codex/release-244-opaque-recovery-07c0 branch September 6, 2026 08:08

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

|| (response.status >= 500 && response.status !== 502)

P2 Badge Gate 502 body reads on function-output candidates

When a Responses request carries only an encrypted reasoning or compaction item—not an encrypted function/custom-tool output—and the upstream returns an unrelated 502 with a slow or stalled body, this widened status gate still clones and drains the response for up to the 5-second bounded-body timeout. shouldAttemptOpaqueBlobRecovery() subsequently rejects that same response because its 502 branch requires outboundResponsesBodyCarriesEncryptedFunctionOutput(), after which the normal error path reads the original body and can wait another timeout. Apply the function-output predicate at this pre-read gate as well so requests that can never use the new 502 recovery do not incur the extra delay.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant