Skip to content

fix: auto-fallback encrypted V2 spawns to native Codex - #3228

Closed
x3M3x wants to merge 2 commits into
lidge-jun:devfrom
x3M3x:codex/fix-v2-native-fallback
Closed

fix: auto-fallback encrypted V2 spawns to native Codex#3228
x3M3x wants to merge 2 commits into
lidge-jun:devfrom
x3M3x:codex/fix-v2-native-fallback

Conversation

@x3M3x

@x3M3x x3M3x commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Encrypted V2 worker payloads require the native ChatGPT backend, but the proxy only attempted native fallback when a user-configured fallback chain existed. With no chain, routed sub-agent models reached the encrypted-task guard and failed with unreadable_encrypted_agent_task.

This change uses the existing native sub-agent roster only for native-only encrypted spawn requests. Ordinary routed sub-agent requests keep their configured routing.

Verification

  • bun run typecheck
  • bun test tests/subagent-model-fallback.test.ts --test-name-pattern "encrypted routed spawn gets" --max-concurrency 1 (blocked before assertions by the Windows credential fixture failing to create its temporary file)
  • git diff --check

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.

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.

@github-actions

github-actions Bot commented Sep 1, 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 1, 2026
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

⏳ DRAFT

  • UI screenshot required.

What to do

  • Add a screenshot of the UI change to the PR description.
  • Tick all four boxes in the PR description once you're done (currently 0/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.

0/4 boxes ticked.

This pull request was already a draft. Its draft status will be preserved after every issue above is resolved.
@x3M3x Tick the boxes once your local CI is green, your branch is on the latest dev commit, and every correct Codex and CodeRabbit finding is resolved.

Hygiene

Deterministic PR hygiene checks passed.

@github-actions
github-actions Bot marked this pull request as draft September 1, 2026 23:27
@coderabbitai

coderabbitai Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

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

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: 25dce9f1-d73f-47ff-bfa0-8d7ef79055bb

📥 Commits

Reviewing files that changed from the base of the PR and between d23eab4 and f1a3c28.

📒 Files selected for processing (2)
  • src/codex/subagent-model-fallback.ts
  • tests/subagent-model-fallback.test.ts

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


📝 Walkthrough

Walkthrough

The fallback resolver now builds a native model chain for encrypted V2 routed spawns when no fallback is configured. A test verifies that the spawn selects gpt-5.5 and rewrites parsed.modelId.

Changes

Subagent fallback behavior

Layer / File(s) Summary
Fallback chain resolution
src/codex/subagent-model-fallback.ts
Imports DEFAULT_SUBAGENT_MODELS. Native-only encrypted V2 tasks without a configured fallback use the primary model followed by the default subagent models. Ordinary routed spawns retain the existing behavior.
Native fallback validation
tests/subagent-model-fallback.test.ts
Adds coverage for an encrypted routed spawn with no configured fallback. The test checks that both to and parsed.modelId become gpt-5.5.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to f1a3c

The change adds native fallback behavior for encrypted V2 spawns and includes a focused regression test; no actionable merge-blocking risk remains beyond normal checks and review.

Suggested reviewers: lidge-jun, luvs01, wibias

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 2 files. 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 V2 spawns now automatically fall back to native Codex models.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@lidge-jun

Copy link
Copy Markdown
Owner

리뷰 · 우선순위 55 / 80

이 PR은 암호화된 V2 서브에이전트 스폰이 실패하는 구멍을 막습니다. 지금 dev(d23eab4) 의 src/codex/subagent-model-fallback.ts 를 보면, applySubagentModelFallback 은 먼저 resolveSubagentFallbackChain 결과(또는 호출부가 넘긴 체인)를 보고, 체인이 null 이면 바로 null 을 돌려줍니다. 그런데 운영자가 subagentModelFallback / 역할별 폴백 / TOML model_fallback 을 하나도 안 넣으면 resolveSubagentFallbackChain 이 의도적으로 null 을 줍니다. 일반 라우팅 스폰에서는 그게 “폴백 안 함”이라서 맞습니다.

문제는 암호화된 V2 자식 작업입니다. src/server/responses/core.ts 는 읽기 불가능한 encrypted agent task 를 만날 때 unreadableEncryptedAgentTasknativeFallbackOnly 로 넘깁니다. 최종 라우트가 정규 ChatGPT 포워드(네이티브 Codex)가 아니면 나중에 unreadableEncryptedAgentTaskResponse 로 막아버립니다. 즉, 기본 프로바이더가 xAI 같은 라우티드 모델이고 폴백 체인이 비어 있으면, 암호화 V2 스폰은 폴백 기회조차 없이 바로 실패합니다. 이 PR은 그 경우에만 DEFAULT_SUBAGENT_MODELS(config.ts 의 gpt-5.5 / gpt-5.6-sol / …) 로 임시 체인을 만들고, 이미 있는 nativeFallbackOnly 필터로 네이티브 Codex만 고르게 합니다. 테스트도 tests/subagent-model-fallback.test.ts 에 “폴백 미설정 + encrypted 플래그 → gpt-5.5” 한 케이스를 추가했습니다.

현재 dev 방향(멀티에이전트 V2, 암호화 작업 복구, 네이티브 전용 폴백)과 잘 맞는 작은 버그픽스입니다. types.ts/config.ts 대규모 분할에 걸려 무효화될 변경도 아닙니다. 다만 PR 설명이 비어 있고 draft + 체크리스트 0/4 라서, 코드는 유망해도 지금 당장 merge-train에 넣기엔 아직 준비가 덜 됐습니다.

라인 609-622 (subagent-model-fallback.ts) - 호출부가 resolvedFallbackChain=null 을 명시적으로 넘기는 경로와, 인자를 생략해 undefined 인 경로를 둘 다 nativeFallbackOnly 일 때 합성 체인으로 처리하는 방향은 맞습니다. core.ts 는 initialSubagentFallbackChain 이 null 이어도 route.codexAccountId === undefined 이면 applySubagentModelFallback 블록에 들어가므로, 이번 버그(라우티드 primary + 빈 체인)는 실제로 구조됩니다.
라인 테스트 신규 - 긍정 케이스만 있고, nativeFallbackOnly=false 이면서 체인 미설정일 때는 여전히 no-op(기존 계약 유지)라는 회귀 테스트가 없습니다. 한 줄이면 충분합니다.
경로/심볼 DEFAULT_SUBAGENT_MODELS - 운영자가 config.subagentModels 로 로스터를 바꿔 둔 경우에도 컴파일 타임 기본값만 씁니다. 의도적일 수 있지만, encrypted 자동 폴백이 대시보드 로스터와 어긋날 수 있습니다.
경로/심볼 core.ts 폴백 게이트 - 체인이 이미 있는데 항목이 전부 비네이티브(예: kimi/xai만)인 경우는 이번 PR 범위 밖이라 여전히 구조되지 않습니다. 제목(“when none is configured”)과 일치하니 버그는 아니지만, 후속으로 네이티브 후보가 하나도 없을 때 DEFAULT를 append 할지 결정이 필요합니다.
PR 설명/체크리스트 - 본문이 readiness checklist만 있고 Summary/Test plan이 비어 있으며 draft·0/4 입니다. 게이트 봇이 이미 막은 상태라 코드 리뷰만으로는 merge 불가입니다.

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

  • 폴백 미설정을 “명시적 비활성”으로 보는 기존 계약과, encrypted V2만 자동 네이티브 폴백을 넣는 예외가 제품적으로 맞는지
  • 합성 체인에 DEFAULT_SUBAGENT_MODELS 고정 vs config.subagentModels ?? DEFAULT_SUBAGENT_MODELS 중 어떤 쪽이 맞는지
  • 체인은 있는데 네이티브 후보가 전무할 때도 DEFAULT를 붙일지, 이번 PR처럼 “미설정일 때만”으로 끝낼지

너의 추천
닫지 말고 유지하세요. 버그 재현과 수정 방향은 현재 dev 기준으로 타당합니다. 작성자(@x3M3x)에게 (1) Summary/Test plan 채우기, (2) 체크리스트 4칸 완료 후 draft 해제, (3) nativeFallbackOnly=false + 체인 미설정 no-op 회귀 테스트 1개 추가, (4) 가능하면 subagentModels 우선 여부를 한 줄로 문서화 요청하세요. 그다음 작은 bug 픽스로 merge-train에 태우면 됩니다. 중복 종료 대상은 아닙니다.

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

@x3M3x

x3M3x commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Added dashboard controls for the global sub-agent fallback chain: ordered add/remove/reorder, availability polling interval, and live save through /api/subagent-model-fallback. The Dashboard already exposed vision sidecar model/backend/reasoning, enable/disable, limits, and timeout controls; no duplicate vision UI was added. GUI build passes; lint:i18n remains environment-blocked by the local Oxlint TypeScript-plugin loader.

lidge-jun added a commit that referenced this pull request Sep 2, 2026
…hout a configured chain (#3239)

An encrypted V2 worker payload needs the native ChatGPT backend, but
applySubagentModelFallback only consulted a fallback chain the operator
configured. With no chain, a routed sub-agent model reached the
encrypted-task guard and failed with unreadable_encrypted_agent_task.

When nativeFallbackOnly is set and no chain exists, build the chain from
DEFAULT_SUBAGENT_MODELS. selectAvailableSubagentModel still drops every
non-forward candidate and isSubagentModelUnavailable still honours disabled
models, quota, and health. Ordinary routed spawns are unchanged.

Source hunks from #3228; the bundled GUI fallback-chain editor is left for
its own feature PR.

Co-authored-by: jun <jun@lidge.dev>
Co-authored-by: x3M3x <amroeid1999@gmail.com>
@lidge-jun

Copy link
Copy Markdown
Owner

The fix landed via maintainer as #3239744d12d02 on dev, with you credited as co-author. Thanks — the diagnosis (no configured chain → routed sub-agent hits the encrypted-task guard) was right, and the fix is exactly the five lines that belong in applySubagentModelFallback.

The bundled GUI fallback-chain editor (Subagents.tsx, SubagentDelegationSection.tsx, nine i18n files) is a separate feature, not part of this bug, and it is what tripped enforce-target here (a description that mentions gui needs a screenshot). If you want it in, please open it as its own PR against dev with a screenshot of the editor — the /api/subagent-model-fallback routes it uses already exist, so it should be a clean feature PR.

Closing this as landed (source half) via the carry.

@lidge-jun

Copy link
Copy Markdown
Owner

Correction: the source fix was reverted in #3242 (2cb592174), so this is not landed after all — I'm sorry for the churn.

What the exact-head CI showed after it merged: tests/agent-task-recovery.test.ts pins a contract that with agentTaskRecovery absent or disabled, an encrypted spawn on a routed model fails fast with a 400 unreadable_encrypted_agent_task and makes zero upstream fetches. Synthesizing a native chain there silently reroutes the spawn to the ChatGPT backend and spends a stored credential the operator never opted into for that model, which is why that contract exists. My review missed that file (it only ran the fallback and security files), so this one is on me, not you.

The behaviour you hit is therefore the documented one: an encrypted V2 spawn on a routed sub-agent model needs an explicit opt-in — either a subagentModelFallback chain that includes a native model, or agentTaskRecovery.enabled: true to decrypt and stay routed. If you think the defaults should change, that is a product decision worth a feature request with the trade-off stated (convenience vs. unrequested native spend), and the GUI editor from this PR would be a natural companion to it.

lidge-jun pushed a commit that referenced this pull request Sep 2, 2026
lidge-jun pushed a commit that referenced this pull request Sep 2, 2026
lidge-jun added a commit that referenced this pull request Sep 2, 2026
…sion audit (#3218)

* docs(devlog): open the bug/PR closeout stack roadmap

* docs(devlog): fold the A-gate import-boundary finding into phase 5

* docs(devlog): record the #3163 and #3166 landings

* docs(devlog): record why #2986 does not land in this train

* docs(devlog): close out the bug/PR closeout stack

* docs(devlog): record the final green CI verdict on dev

* docs(devlog): open the bug-label drawdown roadmap with audit corrections

* docs(devlog): record the Batch A landings and first rebase carry

* docs(devlog): record the Batch B rebase carries

* docs(devlog): record why the rebase service earned its keep

* docs(devlog): record the Batch C rebases and the one real review finding

* docs(devlog): record the #2999 scope boundary that survived execution

* docs(devlog): record Batch D - every bug PR closed

* docs(devlog): record what the PR half of the campaign cost

* docs(devlog): replan the remaining issues to one per cycle

* docs(devlog): carry the i3141 evidence into the replan

* docs(devlog): diagnose i3141 - fix predates the reported version

* docs(devlog): retire the second bundle

* docs(devlog): record the i3141 re-triage action and outcome

* docs(devlog): diagnose i3152 log table jitter

* docs(devlog): i3152 - measurement disproved the layout diagnosis

* docs(devlog): diagnose i3136 slashed-id price lookup

* docs(devlog): diagnose i3150 citation marker passthrough

* docs(devlog): diagnose i3155 capacity plan allowlist

* docs(devlog): i1419 stays open pending crash frames

* docs(devlog): record the i1419 re-triage ask

* docs(devlog): diagnose i2999 publication overwrite race

* docs(devlog): record the i2999 outcome and remaining scope

* docs(devlog): diagnose i2813 as a client-side reserve gate

* docs(devlog): diagnose i1527 residuals as trace-blocked

* docs(devlog): correct i1527 envelope-cap wording (192 blobs, HTTP 400)

* docs(devlog): plan p3193 loopback alpha-search reimplementation

* docs(devlog): record p3193 landing (#3205 -> 53c09a2)

* docs(devlog): plan the main->dev regression audit

* docs(devlog): pin regaudit counts, add tests-only/security passes and the exact-head dispatch

* docs(devlog): record regaudit reviewer verdicts

* docs(devlog): record the exact-head dev CI verdict and Windows classification

* docs(devlog): record the main control run proving the Windows failures predate the range

* docs(devlog): record the pass-1 recount and the #3217 root cause

* docs(devlog): plan i3217 (Spark functions-namespace flattening)

* docs(devlog): record i3217 landing (#3224 -> d23eab4)

* docs(devlog): regaudit2 recount and disposition table

* docs(devlog): regaudit2 CI verdict on d23eab4 and the four PR arrivals

* docs(devlog): plan p3226 (scoped namespace scrub)

* docs(devlog): p3226 audit finding and carry plan

* docs(devlog): record p3226 landing (#3234 -> b732b0d)

* docs(devlog): plan p3227 (combo zero-output incomplete failover)

* docs(devlog): record p3227 landing

* docs(devlog): plan p3228 (encrypted V2 spawn native fallback)

* docs(devlog): record p3228 landing

* docs(devlog): plan p3229 (Codexless originator in task recovery)

* docs(devlog): record p3229 landing and the #3239 regression repair

* docs(devlog): r3239 regression repair record

* docs(devlog): r3239 audit note

* docs(devlog): record p3232 (merged by maintainer)

* docs(devlog): p3232 verification result

* docs(devlog): regaudit3 recount and landing table

* docs(devlog): record the #3239/#3240 revert and correct the #3228 disposition

* docs(devlog): rv3239 revert record

* docs(devlog): rv3239 audit note

* docs(devlog): regaudit3 second-dispatch verdict

* docs(devlog): regaudit3 recount refreshed (#1419 closed by maintainer; count 4)

* docs(devlog): regaudit3 final CI verdict and c-7

---------

Co-authored-by: jun <jun@lidge.dev>
@x3M3x
x3M3x deleted the codex/fix-v2-native-fallback branch September 2, 2026 06:16
@lidge-jun lidge-jun added the landed-via-maintainer Original PR closed after landing via a maintainer merge train label Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working landed-via-maintainer Original PR closed after landing via a maintainer merge train

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants