Skip to content

feat(codex): bind custom models to exact accounts - #1747

Closed
luvs01 wants to merge 1 commit into
lidge-jun:devfrom
luvs01:agent/pin-daybreak-main-when-picker-hidden
Closed

luvs01 wants to merge 1 commit into
lidge-jun:devfrom
luvs01:agent/pin-daybreak-main-when-picker-hidden

Conversation

@luvs01

@luvs01 luvs01 commented Aug 15, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • Add optional row-scoped codexAccountTarget to canonical openai Codex-forward custom models.
  • Expose Automatic/Main/Pool account selection in the dashboard, CLI, and management API.
  • Reuse the existing fixed-account boundary across policy aliases, Responses/compact, translated routes, search, and vision/web-search helpers.
  • Keep repair-only account-bound rows out of active catalogs and client exports, including ocx opencode and ocx export.

Exact base: b81314cd29b78fecb447df882dc4fc1a987434b9
Exact head: 10c11282632215c8971ee6b98f73e5a56f519b85

Why

The old patch inferred physical-main ownership from codexAccountPickerEnabled=false and the Daybreak slug. Picker visibility is not an account-ownership contract, and that rule would fail users whose entitlement belongs to another Pool account.

codexAccountTarget makes the choice explicit, model-row scoped, reusable beyond Daybreak, and convenient in the existing model editor. Omitting it preserves the existing Pool/Direct route.

Contract and compatibility

  • Accepted targets are @main or a currently existing stable Pool account ID.
  • Only canonical openai Codex-forward custom rows can assign a target.
  • A set target is an explicit exact binding. It overrides Direct for that row, fails closed, never rotates or falls back to another account, and does not mutate the active Pool selection.
  • New unknown account IDs are rejected. If an assigned account is later deleted, the row retains the target for repair/re-add but is not offered as a new active choice; persisted settings stay visible for repair and runtime requests fail closed.
  • Bare models, selector-qualified routes, openai-apikey, noncanonical providers, and rows without the field are unchanged.
  • Policy/combo aliases, translated routes, search, compact, vision, and web-search helper calls preserve the binding. Vision and web-search helpers may use different fixed accounts within one turn.
  • Duplicate routed slugs with conflicting/mixed targets fail closed instead of borrowing ordinary Pool/Direct credentials.
  • GUI labels are privacy-safe and disambiguated with safe log labels; tokens, raw ChatGPT identity material, and raw Pool IDs are never rendered.

Atomic writes and older proxies

Target-bearing management writes use dedicated routes:

  • POST /api/custom-models/account-target
  • PUT /api/custom-models/{id}/account-target

Each write carries a transient UUID nonce that is echoed but never persisted. Legacy target-bearing writes are rejected, and an older proxy returns 404 before mutation, so GUI/CLI clients cannot silently save a target that the running proxy ignores. Locked persistence revalidates provider, account, routed-slug, and row-lifecycle state against the latest config snapshot before attesting success.

UI and CLI

The custom-model editor offers Automatic (normal Pool/Direct routing), Main account, and eligible Pool accounts. The same choice is available through ocx models add/edit --codex-account-target; clearing restores Automatic. Offline CLI add uses a locked, revalidated config mutation, while live target writes use the dedicated atomic routes.

A real dashboard pass with synthetic account labels was completed. The screenshot attachment is still pending, so this PR remains draft.

Verification

Exact rebased head 10c1128263:

  • Bun 1.3.14: 62/62 focused selection tests, 333 assertions.
  • Bun 1.4.0-canary.1: 62/62 focused selection tests, 333 assertions.
  • bun run typecheck: pass on both runtimes.
  • bun run privacy:scan: pass on both runtimes.
  • GUI lint:i18n and production build: pass.
  • git diff --check: pass.
  • Codex Security scan 62b2e040-763b-40b2-ac78-36c9fc3e0f62: CLEAN, zero candidates/findings, complete 46/46 changed-source and 7/7 security-surface coverage.
  • Stable patch ID: e7e2de0d01786fbc52524cfc2e73d49862aaef2d.

Patch-equivalent pre-rebase validation:

  • 84/84 focused tests and 312 assertions on both Bun runtimes.
  • Config/CLI/policy extended set: 91/91 on both runtimes, 316 assertions.
  • GUI account-target/i18n set: 11/11 on both runtimes, 83 assertions.
  • GUI build, docs build, lint:i18n, typecheck, privacy, and diff checks passed.
  • Independent exact-range correctness and contract-surface reviews found no P0-P2 defects.

The full repository suite is not claimed green. On this Windows host, two existing LRU stress tests exceeded the default 5-second timeout but passed individually at 30 seconds; the existing unreadable-file ACL cleanup fixture in codex-config-generation.test.ts also reports EACCES. Maintained exact-head cross-platform CI is still required.

Checklist

  • Account ownership is explicit and row-scoped, not inferred from picker visibility or a model literal.
  • Omitted configuration preserves existing Pool/Direct behavior.
  • Fixed-account, deletion, retry, policy, sidecar, export, lifecycle, privacy, and compatibility boundaries received independent review.
  • Attach the dashboard screenshot and obtain maintained exact-head CI.

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.

@coderabbitai

coderabbitai Bot commented Aug 15, 2026 •

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 656fb889-7698-4e4f-8317-4ed73a27b1d8

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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 Aug 15, 2026
@github-actions

github-actions Bot commented Aug 15, 2026 •

Copy link
Copy Markdown
Contributor

⏳ DRAFT

  • hygiene: unsponsored_surface.

What to do

  • Fix unsponsored_surface — This changes an authentication, workflow, release-automation, or dependency surface. MAINTAINERS.md requires security review for these; ask a maintainer to apply maintainer-sponsored once they have reviewed it. Paths: src/codex/auth-api.ts, src/codex/auth-context.ts.
  • Tick all four boxes in the PR description once you're done (currently 1/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.

1/4 boxes ticked.

UI screenshot waived by a maintainer comment.
This pull request was already a draft. Its draft status will be preserved after every issue above is resolved.
@luvs01 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.

@luvs01
luvs01 force-pushed the agent/pin-daybreak-main-when-picker-hidden branch from af4e96b to 1d99b95 Compare August 15, 2026 11:58
@github-actions github-actions Bot added the intake: hygiene-blocked Deterministic PR hygiene checks failed label Aug 15, 2026
@luvs01 luvs01 changed the title fix(codex): pin picker-hidden Daybreak to physical main feat(codex): bind custom models to exact accounts Aug 15, 2026
@github-actions github-actions Bot added enhancement New feature or request and removed bug Something isn't working labels Aug 15, 2026
@luvs01
luvs01 force-pushed the agent/pin-daybreak-main-when-picker-hidden branch from 1d99b95 to a8f5eb9 Compare August 16, 2026 04:08
@luvs01
luvs01 force-pushed the agent/pin-daybreak-main-when-picker-hidden branch from a8f5eb9 to 10c1128 Compare August 16, 2026 07:21
@Ingwannu

Copy link
Copy Markdown
Owner

The explicit account-binding concept is understandable, but this submitted PR is no longer reviewable as a merge candidate: it is 559 dev commits behind, hygiene-blocked, and mixes a credential/routing boundary with a very large GUI, i18n, CLI, API, docs, and test sweep.

Under the current maintainer workflow I will not approve or merge the GUI/text surfaces directly. If the owner still wants this feature, recut a focused current-dev runtime/API PR defining only the exact-account binding and fail-closed credential behavior. Put GUI/i18n/docs in a separate follow-up for owner/UI review, include the required screenshot, and rerun the security and exact-head tests against the current account lifecycle. The old head should not be rebased wholesale.

@luvs01
luvs01 force-pushed the agent/pin-daybreak-main-when-picker-hidden branch 2 times, most recently from 13e775b to 10c1128 Compare August 19, 2026 06:36
@lidge-jun

Copy link
Copy Markdown
Owner

리뷰 · 우선순위 39 / 80

dev 기준 이 PR은 OcxCustomModel.codexAccountTarget으로 canonical openai Codex-forward custom row를 @main 또는 현재 존재하는 Pool account id에 고정합니다. picker visibility나 Daybreak slug로 main을 추정하던 경로를 버립니다. src/codex/custom-model-account-target.ts가 grammar/provider/assignment을 나누고, 같은 routed slug에 target 있는 행과 없는 행이 섞이거나 target이 다르면 throw합니다. 삭제로 orphan이 된 값은 resubmit만 허용하고 catalog에서는 filterModelsByCustomRouteAvailability로 빼며 runtime은 fail-closed입니다. 계약은 분명합니다. 다만 Draft, hygiene-blocked, mergeable: UNKNOWN, 87파일/+4548이라 merge 우선순위는 낮습니다.

src/router.ts는 explicit-provider 해석 뒤에 customModelCodexAccountIdForRoute를 붙이고, 값이 있으면 codexAccountMode: "pool", codexAccountBinding: "custom-model"을 넣습니다. 활성 Pool 선택을 바꾸지 않는다고 주석에 적혀 있습니다. 같은 helper가 assemble/evaluator/core/compact/search/vision-sidecar에도 퍼집니다. 한 경로라도 helper를 빼면 그 요청만 일반 Pool/Direct로 떨어집니다. 이 diff에서 router 적용은 slash explicit-provider 분기가 중심이라, bare/selector-qualified/combo 경로가 모두 같은 함수를 타는지 테스트 표가 있어야 합니다.

쓰기는 전용 POST /api/custom-models/account-target와 PUT /api/custom-models/{id}/account-target입니다. generic PUT은 body나 기존 row에 target이 있으면 target-aware route required 409입니다. nonce는 UUID-v4이고 persist하지 않습니다. older proxy는 404로 침묵 저장을 막습니다. lock 안에서 provider/account/slug/lifecycle을 다시 봅니다. __main__ sentinel은 public grammar에서 거절되고 @main만 MAIN_CODEX_ACCOUNT_ID로 정규화됩니다. GUI는 raw Pool id를 렌더하지 않는다고 합니다.

본문은 screenshot 미첨부와 full suite 미통과를 인정합니다. export/ocx opencode에서 repair-only row를 빼는 변경은 CLI 파일에도 있습니다. 이 레이어는 계정 고정이라 실수하면 잘못된 계정으로 청구됩니다.

해결방안: (1) hygiene를 통과시키고 현재 dev에 rebase한 뒤 screenshot을 붙이고 Draft를 푸십시오. (2) route 종류별로 customModelCodexAccountIdForRoute 호출 표를 테스트로 고정하십시오. 빠져 있는 분기가 있으면 일반 Pool로 떨어지지 않게 같은 helper를 넣으십시오. (3) 삭제된 account의 persist/hide/runtime-fail 세 상태를 한 테스트에 묶으십시오. (4) nonce를 로그/DTO에 raw로 남기지 않는지 확인하십시오. (5) 87파일은 기능 하나라도 리뷰 비용이 크니, docs locale과 GUI i18n을 후속 PR로 나눌 수 있으면 나누십시오.

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

@luvs01

luvs01 commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator Author

This draft was built against a now-distant dev and combines an authentication/routing boundary with GUI, CLI, localization, documentation, export, and helper-route changes across 87 files. Since submission, dev has gained native Daybreak catalog support and per-account entitlement-aware fail-closed routing, replacing the feature's original urgent use case, and maintainer review explicitly advised against rebasing this head wholesale. Closing it keeps the review queue accurate; if persistent custom-model account binding is still needed later, it should return as a small current-dev, opt-in runtime/API change with unsupported indirections rejected and presentation surfaces handled separately.

@luvs01 luvs01 closed this Aug 20, 2026
@luvs01
luvs01 deleted the agent/pin-daybreak-main-when-picker-hidden branch September 20, 2026 06:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request intake: hygiene-blocked Deterministic PR hygiene checks failed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants