Repository navigation
fix(combo): fail over Astra tool routing mismatch - #5142
Conversation
|
Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configurationConfiguration used: Repository: lidge-jun/opencodex/.coderabbit.yaml Review profile: ASSERTIVE Plan: Advanced Run ID: 📒 Files selected for processing (4)
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository: lidge-jun/opencodex/.coderabbit.yaml Review profile: ASSERTIVE Plan: Advanced Run ID: 📒 Files selected for processing (4)
Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review. 📝 WalkthroughWalkthroughThe failover classifier now recognizes an exact ChangesRouting failover
Priority: ⬇️ Low Estimated code review effort: 2 (Simple) | ~10 minutes Change: Bug fix Sequence Diagram(s)sequenceDiagram
participant Client
participant ComboFailover
participant FirstResponsesTarget
participant BackupResponsesTarget
Client->>ComboFailover: Send function_call_output request
ComboFailover->>FirstResponsesTarget: Forward request
FirstResponsesTarget-->>ComboFailover: 400 reasoning_effort routing refusal
ComboFailover->>ComboFailover: Classify refusal as request-local
ComboFailover->>BackupResponsesTarget: Forward unchanged request
BackupResponsesTarget-->>Client: 200 successful response
Merge Risk: ⚪ Minimal · up to The documented failover behavior remains internally consistent, and no actionable merge risk remains. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
|
✅ Deterministic PR hygiene checks passed. |
⏳ DRAFT
What to do
Review readiness checklist
0/4 boxes ticked. Automatic draft conversion failed. Please convert this pull request to a draft manually until every box above is ticked. |
311bbab to
18879cf
Compare
리뷰 · 우선순위 48 / 80콤보의 첫 타깃이 한 가지 400을 주면, 콤보를 끊지 않고 다음 타깃으로 넘겨요. gpt-6-astra에 함수 도구와 reasoning_effort를 같이 실으면, 어떤 Xhub 쪽이 "이 요청은 /v1/chat/completions로 갔다"는 400을 돌려요. OpenCodex는 openai-responses로 보냈는데도 그래요. 다른 자격 증명은 같은 요청이 돼요. 예전에는 이 400이면 콤보가 거기 끝났어요. 이제는 그 400이 정해 둔 모양일 때만 넘겨요. 상태 번호는 400이어야 하고, error.code는 null이어야 하고, param은 reasoning_effort여야 하고, 문장은 한 글자까지 같아야 해요. 모델 이름은 gpt-6-astra이거나, 뒤에 2026-09-03처럼 날짜만 붙은 이름만 받아요. 미리보기 이름, 날짜 칸이 다른 이름, 짧은 문장, 다른 param, 다른 code는 그대로 멈춰요. 넘길 때 그 타깃을 잠시 막지는 않아요. 요청도 고치지 않아요. 테스트는 스트림이든 아니든, 같은 도구 결과가 두 타깃에 가는지 봐요. 베이스는 main이에요. types.ts와 config.ts를 나누는 일과는 관계없어요. 이 문장을 고치는 다른 열린 PR은 없어요. 라인 베이스 - 라인 src/combos/failover.ts 402행 - 문장 끝의 마침표까지 같아야 넘어가요. 실제로 돌아온 400에 요청 번호가 붙거나, param이 reasoning.effort이면 안 넘어가요. 단위 테스트의 넘김은 바깥 code를 invalid_request_error로 넣어요. 서버는 이 에러의 code가 null이면 바깥 code를 비워요 (src/server/responses/core-errors.ts 70행). 비어 있어도 이 함수는 넘어가게 되어 있어요. 그 호출은 hop 테스트에 없어요. 메인테이너의 판단이 필요한 지점 실제로 받은 Xhub 400이 이 문장과 같은지 봐 주세요. 한 글자만 달라도 테스트는 통과하고, 그 장애는 그대로예요. 다음 타깃도 같은 잘못된 쪽이면 또 400이에요. 콤보는 타깃마다 한 번만 가서 끝나기는 해요. reasoning_effort를 none으로 지우지는 않아요. 문서에 적어 둔 그대로예요. 이대로 둘지 정해 주세요. 너의 추천 일치를 좁혀 둔 것은 맞아요. 닫을 중복은 없어요. main에는 넣지 마세요. 베이스를 dev로 바꾸고, 최신 dev 위에 올린 다음, 받은 400 원문이 정규식과 같은지만 보면 돼요. 이 댓글은 grok-bot이 작성했습니다 |
18879cf to
2bb2678
Compare
추가 리뷰 · 우선순위 36 / 80지난 리뷰 뒤에 보는 가지만 바뀌었어요. 12:39에 가지를 다시 밀어 넣었고, 베이스가 main에서 dev로 옮겨졌어요. 400을 넘기는 규칙은 그대로예요. 문장이 한 글자까지 같아야 하고, 그 타깃을 잠시 막지는 않아요. 이 머리는 dev보다 커밋 4개가 뒤예요. 뒤의 네 커밋은 이미지 프롬프트, 웹소켓, 사이드밴드 프레임, 히스토리 잡이에요. 이 PR이 고친 파일과는 안 겹쳐요. 제목에는 아직도 라인 제목 - 가지를 고친 뒤에도 라인 src/combos/failover.ts - 문장 끝의 마침표까지 같아야 넘어가요. param이 reasoning.effort이거나, 문장 뒤에 요청 번호가 붙으면 안 넘어가요. 이 부분은 안 고쳤어요. 라인 tests/routing/router-combo-failover-classification.test.ts - 넘김 테스트는 바깥 code를 invalid_request_error로 넣어요. 서버는 안쪽 code가 null이면 바깥 code를 안 넘겨요. 빈 값이어도 이 함수는 넘어가고, 서버 테스트가 그 길을 타요. 단위 테스트의 넘김 호출만 서버가 넣는 값과 달라요. 메인테이너의 판단이 필요한 지점 실제로 받은 Xhub 400이 이 문장과 같은지 봐 주세요. 한 글자만 달라도 테스트는 통과하고, 그 장애는 그대로예요. 다음 타깃도 같은 잘못된 쪽이면 또 400이에요. reasoning_effort를 none으로 지우지는 않아요. 이대로 둘지 정해 주세요. 너의 추천 가지는 맞아요. 닫을 중복은 없어요. 제목의 이 댓글은 grok-bot이 작성했습니다 |
) * refactor(codex,tests): split two files back under their size caps The file-size ratchet reported two offenders on dev. src/codex/history-provider.ts reached 2009 lines and is not in the baseline, so it tripped NEW_OVERSIZED at the 2000-line threshold. tests/server/server-combo-failover-e2e.test.ts reached 4192 against a committed cap of 4166. Both came from the batch merged just before: #5137 added the paginated-openai verdict to the history preflight, and #5142 added a tool-routing failover case. Raising either cap is not available. updateBaseline only ever lowers a cap and tests/ci-workflows/file-size-ratchet.test.ts asserts that, so a baseline edit would fail the same gate. Trimming the rationale comments those two changes carry would have fit the line budget and is the wrong trade: the comments are why the verdicts are readable at all. src/codex/history-rollout-read.ts takes the reading side of rollout JSONL files: the session_meta fold and the thread fields a quarantine restore reconstructs. The cut follows a seam rather than a line count. Everything moved reads a file and returns plain data; everything left behind writes a database or a backup manifest. history-provider.ts re-exports the public names, so no importer changes. tests/helpers/combo-tool-routing-cases.ts follows the register-cases seam the forced-effort, context-overflow and context-headroom groups already use in that file. The case body is unchanged; only its home moved, and it still runs inside the same describe with the same isolated homes, mocks and cleanup. No local suite, focused test, typecheck or build was run. Exact-head hosted CI is the execution evidence. * test(codex): verify the Reserve cache on disk instead of the write flag Three Reserve catalog lifecycle cases fail on the dev tip's macOS shards with refreshOutcome committed, catalogExists true, catalogWritten false and cacheSynced false. The fixture's oracle required cacheSynced, and #5108 made that flag report whether bytes were written, so a sync that finds the desired bytes already on disk now answers false. The production meaning is the one to keep. src/cli/index.ts and src/cli/dispatch.ts gate restart and reporting on catalogWritten or cacheSynced, and a start that changed nothing should not claim it did. The stale assertion is the fixture's. Deleting the assertion is not available either: a broad catch inside the refresh also yields false, so dropping it would stop distinguishing a no-op from a failure. Instead the child now requires the committed verdict and then reads the cache back, proving the active catalog's slugs appear in the cache file in the same order. That is independent of the write flag and of the cache document shape, and every existing Reserve assertion is untouched. Root cause analysis by the contract-campaign task, which confirmed the genuine changed-source case still passes and only the byte-identical no-op trips the old oracle. No local suite, focused test, typecheck or build was run. Exact-head hosted CI is the execution evidence. --------- Co-authored-by: lidge-jun <lidge-jun@users.noreply.github.com>
Summary
Root cause
OpenCodex dispatched through the
openai-responsesadapter, but one Xhub credential/backend returned a structured 400 claiming the request used/v1/chat/completions; the same Responses tool workflow succeeded through another credential. The combo previously treated that target-local mismatch as terminal.Validation
bun x tsc --noEmitbun test tests/routing/router-combo-failover-classification.test.ts tests/server/server-combo-failover-e2e.test.ts(233 pass)bun scripts/structure-ssot.tsSummary by CodeRabbit
Review readiness checklist
This PR stays in draft until every box below is ticked. Tick all four boxes once the requirements are met:
All CI tests are green on my local testing.
I pushed my PR to the latest dev commit.
I resolved all correct Codex and CodeRabbit findings.
My PR is ready for review.