Skip to content

fix(combos): hop on definite zero-output context overflow - #4659

Draft
RHODIZSECURITY wants to merge 2 commits into
lidge-jun:devfrom
RHODIZSECURITY:fix/combo-definite-context-overflow-20260914
Draft

RHODIZSECURITY wants to merge 2 commits into
lidge-jun:devfrom
RHODIZSECURITY:fix/combo-definite-context-overflow-20260914

Conversation

@RHODIZSECURITY

Copy link
Copy Markdown
Contributor

Root cause

A heterogeneous combo can receive a zero-output context overflow from a smaller-context target as a generic 5xx/502-style upstream failure whose structured outer code is upstream_server_error, while the provider message clearly says the request exceeds that model's context window.

Today the combo classifier can normalize that prose to context_length_exceeded and then stop the chain, so a later target with a larger context window is never tried. A contradictory envelope must still remain terminal: an outer context_length_exceeded token beside an unrelated message such as Unsupported parameter: user is not sufficient evidence to replay.

Fix

  • Add a bounded isDefiniteContextOverflow() classifier that authorizes a hop only from concrete context-window prose, with strict wrapper/JSON unwrapping and a 16 KiB bound.
  • Treat definite context overflow as request-shaped for cooldown purposes, so a healthy target is not cooled just because the request is too large for that model.
  • Preserve terminal precedence for cancellation, cyber/origin policy, and non-replayable post-send transport ambiguity.
  • Keep contradictory or unrelated invalid-request envelopes fail-closed.

Regression coverage

The focused current-dev suite verifies:

  • zero-output context overflow 502 -> healthy backup 200;
  • ordinary context overflow 400 -> larger-context backup 200;
  • contradictory optional-control envelopes remain terminal;
  • no cooldown is assigned for a definite request-shape overflow;
  • policy fallback can advance on the same definite upstream context condition.

Verification on exact head 2e0337394:

  • bun test tests/routing/router-combo-failover-classification.test.ts tests/server/server-combo-failover-e2e.test.ts tests/codex-integration/combos.test.ts tests/routing/routing-policy-fallback.test.ts -> 300 PASS / 0 FAIL, 1,503 assertions.
  • bun x tsc --noEmit -> PASS.
  • git diff --check -> PASS.

This was reproduced on the RHODIZ HomeLab failover path while auditing combo/rhodiz-coding-primary; the local 2.55 hotfix already uses the same bounded semantic rule. No provider credentials or private request contents are included here.

Review readiness checklist

  • Focused local tests are green on the exact head.
  • Branch is based on current dev at 836511b9c when opened.
  • Resolve all correct hosted review findings.
  • Mark ready after hosted CI/review is complete.

@coderabbitai

coderabbitai Bot commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

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

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the bug Something isn't working label Sep 14, 2026
@github-actions

github-actions Bot commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

⏳ DRAFT

  • review readiness checklist open (2/4 boxes ticked).

What to do

  • Tick all four boxes in the PR description once you're done (currently 2/4).

Review readiness checklist

  • ✅ 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.

2/4 boxes ticked.

This PR stays in draft until every box above is ticked.

@lidge-jun

Copy link
Copy Markdown
Owner

리뷰 · 우선순위 73 / 80

이 PR은 이종(heterogeneous) 콤보에서 작은 컨텍스트 모델이 요청을 못 담아서 내는 실패를, 지금은 체인 전체 종료로 처리하는 구멍을 고칩니다. 재현 이야기는 분명합니다. 앞 타깃이 제로 출력 컨텍스트 오버플로를 일반적인 upstream_server_error/502 껍데기에 넣어 보내고, 메시지 본문만 exceeds the context window 같은 확실한 문장일 때, 지금 dev(09067c586, #4655 갓파일 round3 팁)의 comboFailureDecision은 그 껍데기 코드를 보고 그냥 멈추거나 (혹은 분류기가 context_length_exceeded로 정규화한 뒤) 더 큰 창을 가진 다음 타깃을 시도하지 않습니다. 같은 요청이 뒤 타깃에서는 통과할 수 있는데도 콤보가 한 타깃에서 끝납니다.

고치는 곳은 src/combos/failover.ts 한 파일과 회귀 테스트 네 곳입니다. 핵심은 새 isDefiniteContextOverflow(message)입니다. JSON 코드 토큰만 믿지 않고, 메시지 본문에서 컨텍스트 창 초과 문장을 확인합니다. OpenCodex 자신의 Provider error N: {...} 래퍼를 최대 4단까지 벗기고, 16 KiB를 넘기면 바로 거절합니다. 확정되면 (1) comboFailureDecisionhop을 주고, (2) comboFailureCooldownScopenone이라서 건강한 타깃을 쿨다운하지 않습니다. 동시에 예전 정지 목록에서 context_length_exceeded를 빼서, 분류기가 그 코드로 정규화한 경우도 더 이상 무조건 정지하지 않습니다. 취소(499), 사이버/오리진 정책, 전송 후 비재현 수송 코드(upstream_no_response 등)는 그대로 정지 우선입니다.

현재 dev와 맞춰 보면, isProviderTargetContextOverflow는 이미 벤더 5059 / invalid_request_prompt_too_long / Prompt N > M maximum context length 형태만 타깃 로컬 hop으로 봅니다. input_admission_refused(#1524)도 hop입니다. 그런데 업스트림이 구조화 코드 없이, 또는 upstream_server_error 껍데기로 같은 사실을 말할 때는 아직 정지 쪽에 가깝습니다. src/server/responses/core.ts 주석도 아직 context_length_exceeded still stops라고 적혀 있고, 정책 폴백 테스트도 예전에 “업스트림 CLE는 체인 정지(#1524 거울 계약)”를 문서화했습니다. 이 PR은 그 제품 결정을 바꿉니다. 콤보뿐 아니라 handleResponsesWithPolicyFallback도 같은 comboFailureDecision을 쓰므로, 정책 후보도 다음 모델로 넘어갑니다. 갓파일 round3(#4655)이 쪼갠 config/providers/registry / 카탈로그 / 어댑터 모놀리스는 건드리지 않아서 close-don't-rebase 대상은 아닙니다. 초안 기준 커밋은 836511b9c이고 팁은 그 뒤 #4655/#4657이 올라왔으니, ready 전에 dev 재기지가 필요합니다. 형제 초안 #4656(전송 예산 아래 선언 타깃 보존), #4652(Claude done-only tool args)와 같은 저자·콤보 축입니다.

테스트는 분류·쿨다운·e2e·정책 폴백을 같이 뒤집습니다. 제로 출력 502 SSE → 백업 200, 평범한 context 400 → 더 큰 창 백업 200, 모순 봉투(코드만 CLE이고 메시지는 다른 거절)는 정지, 확정 오버플로에는 쿨다운 없음. 로컬 헤드에서 관련 스위트 300 PASS와 tsc --noEmit을 주장합니다. 방향은 맞고, 실사용 콤보에서 “앞 모델만 작고 뒤는 큰데 전체가 죽는” 체감 버그에 직접 닿습니다. 다만 ‘메시지에 컨텍스트 문장이 있다’는 휴리스틱의 폭과, 코드 토큰만 있는 경우까지 hop으로 연 범위는 메인테이너가 한 번 잠가야 합니다.

라인 454-491 (failover.ts, isDefiniteContextOverflow) - JSON 파싱이 실패하면 소문자 부분 문자열로 hop을 허가합니다. too many tokens, maximum context length 같은 짧은 구문은 컨텍스트와 무관한 400/5xx 본문에도 우연히 들어갈 수 있어, 의도와 다른 타깃으로 hop할 여지가 있습니다.
라인 (isDefiniteContextOverflow, plain-text 분기) - 메시지 전체가 정확히 context_length_exceeded 문자열이면 hop합니다. 주석은 “JSON 코드 토큰만으로는 재시도 허가하지 않는다”인데, 코드 토큰이 메시지 본문 전체로 온 경우에는 hop이 됩니다. 테스트도 그 방향으로 바뀌었습니다.
경로 src/combos/failover.ts comboFailureDecision 정지 목록 - context_length_exceeded를 목록에서 제거해, 분류기가 그 코드로 정규화한 모든 경로가 이제 hop 후보입니다. 제로 출력 502 재현보다 제품 범위가 더 넓습니다.
경로 tests/routing/routing-policy-fallback.test.ts - 예전 “업스트림 CLE는 체인 정지(#1524 거울)” 계약을 깨고 다음 정책 후보로 진행합니다. 콤보 수정처럼 보이지만 정책 폴백 의미도 같이 바뀝니다.
경로 src/server/responses/core.ts 주석(~4523) - 이 PR이 코드를 바꾸면 그 주석(“CLE still stops”)은 거짓이 됩니다. 주석/문서 정리가 빠져 있습니다.
경로 PR 기준선 - 초안이 836511b9c 기준이고 현재 dev09067c586(#4655/#4657)입니다. 충돌 가능성은 낮아 보이지만 ready 전 재기지와 같은 스위트 재실행이 필요합니다.

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

너의 추천
방향은 유지하되 ready 전에 (1) 현재 dev 09067c586에 재기지, (2) too many tokens 같은 짧은 구문을 더 구체적인 컨텍스트 창 문장으로 좁히거나 테스트로 오탐 경계를 명시, (3) core.ts의 CLE-stops 주석을 새 의미에 맞게 수정, (4) 정책 폴백 계약 변경을 PR 본문에 한 줄로 명시하세요. 그다음 초안 체크리스트를 채우고 ready로 올리면 됩니다. 갓파일 모놀리스 무효화는 아니므로 close-don't-rebase 대상이 아닙니다.

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

Co-authored-by: RHODIZ IT <info.rhodiz@gmail.com>
@lidge-jun
lidge-jun force-pushed the fix/combo-definite-context-overflow-20260914 branch from 2e03373 to 47146fa Compare September 15, 2026 10:37
Keep every assertion registered under the existing suite isolation and cleanup hooks. Static source inspection only; tests not executed on this connected host.

Co-authored-by: RHODIZ IT <info.rhodiz@gmail.com>
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.

2 participants