Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
57a0131
fix(codex): enforce and explain automatic plan exclusions
lidge-jun Sep 12, 2026
718a7cc
feat(codex): add reset-first pool ordering through canonical settings
lidge-jun Sep 12, 2026
1c8457a
fix(codex): retain reset-first affinity when threshold is disabled
lidge-jun Sep 12, 2026
5c648ea
test(codex): require a usable reset-first recovery alternate
lidge-jun Sep 12, 2026
e900742
feat(codex): bind quota observations to credential publication identity
lidge-jun Sep 12, 2026
19cbe82
merge: preserve current dev contracts for #4375
lidge-jun Sep 12, 2026
29d2434
merge: preserve current dev contracts for #4369
lidge-jun Sep 12, 2026
a1f24df
merge: retain current dev and eligibility delivery records
lidge-jun Sep 12, 2026
7f3ba61
test(codex): include plan exclusion in next-session badge coverage
lidge-jun Sep 12, 2026
a3dae34
docs: refine fenced quota history contracts for the follow-up
lidge-jun Sep 12, 2026
e2d213b
feat(codex): retain bounded credential-fenced quota observations
lidge-jun Sep 12, 2026
0d98205
fix(codex): harden quota history dates and producer regression evidence
lidge-jun Sep 12, 2026
584ba3f
feat(codex): estimate effective capacity from observed quota intervals
lidge-jun Sep 12, 2026
8845f63
fix(codex): exclude unknown capacity scope and report insufficient ev…
lidge-jun Sep 12, 2026
e7eda98
[skip ci] merge: carry origin/dev into #4375
lidge-jun Sep 13, 2026
4baf438
[skip ci] merge: carry #4375 and origin/dev into #4404
lidge-jun Sep 13, 2026
23e892f
[skip ci] merge: carry #4404 and origin/dev into #4408
lidge-jun Sep 13, 2026
cd32757
[skip ci] merge: carry #4408 and origin/dev into #4361
lidge-jun Sep 13, 2026
1269383
[skip ci] merge: carry #4361 and origin/dev into #4369
lidge-jun Sep 13, 2026
ed72770
[skip ci] merge: carry audio-landed origin/dev into #4375
lidge-jun Sep 13, 2026
dd48035
[skip ci] merge: carry audio-landed #4375 into #4404
lidge-jun Sep 13, 2026
659fc53
[skip ci] merge: carry audio-landed #4404 into #4408
lidge-jun Sep 13, 2026
e9c59c6
[skip ci] merge: carry audio-landed #4408 into #4361
lidge-jun Sep 13, 2026
de7c5eb
[skip ci] merge: carry audio-landed #4361 into #4369
lidge-jun Sep 13, 2026
1ec88ef
[skip ci] merge: carry origin/dev #4351 into #4375
lidge-jun Sep 13, 2026
9a6156e
[skip ci] merge: carry #4375 and origin/dev #4351 into #4404
lidge-jun Sep 13, 2026
5f5a6bc
[skip ci] merge: carry #4404 and origin/dev #4351 into #4408
lidge-jun Sep 13, 2026
ad47edf
[skip ci] merge: carry #4408 and origin/dev #4351 into #4361
lidge-jun Sep 13, 2026
c19c161
[skip ci] merge: carry #4361 and origin/dev #4351 into #4369
lidge-jun Sep 13, 2026
86cf983
[skip ci] merge: carry origin/dev #4446 into #4375
lidge-jun Sep 13, 2026
66a54d7
[skip ci] merge: carry #4375 and origin/dev into #4404
lidge-jun Sep 13, 2026
65d482c
[skip ci] merge: carry #4404 and origin/dev into #4408
lidge-jun Sep 13, 2026
228854b
[skip ci] merge: carry #4408 and origin/dev into #4361
lidge-jun Sep 13, 2026
7d91f9c
[skip ci] merge: carry #4361 and origin/dev into #4369
lidge-jun Sep 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions devlog/_plan/260912_accounts/000_plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,5 @@ Two design follow-ups encountered inherited-model capacity errors; one same-hand
## Roadmap cycle outcome

Independent design reflection and A re-audit passed with the source restrictions in 001_roadmap_audit.md. B freezes the contracts as documentation only. C checks document paths/numbering and git whitespace; local product suites NOT RUN. D next direction: execute 010_callback.md independently, then the remaining dependency-ordered cycles. Runtime behavior has not improved yet; the rejected hypotheses were native history identity by sentinel alone, attempt timing inferred from untimed attempts, and one-shot implying one physical request through a retrying primitive.

History P split:048_history_identity.md supplies stable publication identity and fenced writer capture before050 history. This is a new foundation cycle, registered in the same goalplan; intended manual chain history-identity → history → capacity. It is independent of reset-first. Staged login samples are omitted until a fenced post-publication observation; native history remains nondurable and excluded from capacity.
2 changes: 2 additions & 0 deletions devlog/_plan/260912_accounts/020_eligibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ Field chain: existing excludedPlans config create/save/load → same normalized
MODIFY existing `tests/codex-integration/codex-pool-plan-exclusion.test.ts`: replace last-account soft fallback test with none/preview none; test normalized plan update and explicit fixed route. Extend account API/CLI and card tests for reason and renewal clearing. Sync ownership docs and providers configuration pages that describe the old soft exception. Retain source attribution of #4238; no recarry of already-landed commits. Local tests/build/typecheck NOT RUN. Hosted CI plus rendered artifact from final tip supplies execution proof.

Exclusion reason derives from the routing config plan, not a display-only freshly observed plan if persistence failed. This preserves truth between selection and explanation.

P revalidation on dev d6fb87197a: keep exported existing predicate in routing.ts; pass runtimeConfig into both poolAccountDto calls. Alongside closed selectionExcludedReason include selectionExcludedPlan from the same routing config when excluded, so a display-only fresh WHAM tier cannot mislabel the reason. CLI/card render this policy plan. Exact GUI type owner is hooks/useCodexAccountPool.ts; component type file re-exports it. Docs source is guides/codex-integration.md in every locale; revise all-excluded fallback paragraphs there. Callback D delivered PR4352 and left hosted acceptance open; this cycle is independent from current dev.
9 changes: 9 additions & 0 deletions devlog/_plan/260912_accounts/021_eligibility_delivery.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Plan exclusion completion

Built on already-landed #4238, independently from current dev d6fb87197a. Existing normalized predicate is shared with the account DTO; both preview and real automatic fallback reject excluded plans when no eligible account remains. Explicit account-qualified routes retain normal auth, pause and entitlement checks. Native main remains exempt.

CLI and dashboard display the policy's routing-plan reason separately from credential health and a possibly newer display-only plan. The automatic Set-as-next action is suppressed for excluded rows because pinning does not bypass this policy; explicit account-qualified routes remain available. All nine UI locale catalogs and eight affected integration guides are synchronized. Source ownership docs link the canonical plan-exclusion contract.

Regression sources cover all-excluded preview/resolve, renewal, explicit route with pause/reauth, API reasons, CLI normalization and card display/renewal. No new test file or dependency. Local suites/build/typecheck/install: NOT RUN. Hosted CI and rendered preview remain pending. Source searches: isCodexAccountPlanExcluded, getPoolAccountPlan, poolAccountDto, CodexAccountEntry, selection guards and excludedPlans docs; reused the existing predicate rather than a parallel policy.

Prior callback cycle delivered PR4352 and remains pending hosted verification. This is an independent dev PR, with no callback code and no manual chain dependency.
7 changes: 7 additions & 0 deletions devlog/_plan/260912_accounts/022_eligibility_ci_repair.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Eligibility hosted regression repair

Exact-head run34680496052 at a1f24df5ed90848f32d2499303b22620d91eed42 failed in Linux test4/4 job103523074988 and macOS2/2 job103523074889. The reset-ticket source oracle still required the old next-session guard without plan exclusion. The implementation correctly retained all health guards and added plan exclusion.

The oracle now also requires the plan-exclusion guard, preserving ticket co-render and all health checks. A rendered regression fixture confirms eligible accounts show next-session and tickets together; excluded accounts retain tickets and omit next-session. No production code changed. No assertion was removed or loosened. Local suites/build/typecheck/install NOT RUN; remote final-head verification follows.

Other failures in these runs concern Cline registry/localization/asset/test-layout and native history restoration. They are recorded in task scratch with exact job logs for owner integration; no other-lane files were changed. The parent-updated branch was fast-forwarded without rebase or merge commit. Hostgoal remains blocked and FSMB is unchanged; no new completed PABCD cycle is claimed for this source repair.
8 changes: 8 additions & 0 deletions devlog/_plan/260912_accounts/030_reset.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,11 @@ Additional MODIFY `src/oauth/pool-settings-capability.ts` and `src/server/manage
Field chain: CLI/GUI strategy creation → canonical PUT parser → config.accountPoolStrategy write → config load + canonical GET parser → pool rotation/preview/failover, CLI and GUI display. Audit every existing strategy comparison/default, not just the union. No schema migration or new dependency. Exact contributor diff remains `.tmp/accounts-20260912/pr4080.diff` during planning; changes are adapted to current callers before B.

Extend regression sources for canonical PUT/GET/save/reload, legacy endpoint, non-Codex rejection, tied/missing/elapsed resets, threshold zero, priorities, affinity and failover. Existing #4080 test cases are retained/adapted. Update all source ownership docs; screenshot of final rendered strategy control is included with PR. Local suites/build/typecheck/install NOT RUN; final head hosted CI supplies proof. #3376 remains partial until history/capacity; monthly/Anthropic/latest-first scope is reported separately.

P revalidation: #4080 head unchanged. Current pool-rotation.ts is a compatibility facade, so Codex parser/normalizer live in existing src/oauth/pool-kernel.ts leaf and are reexported. Canonical GET DTO and PUT parser use Codex-specific parser only for kind=codex. Use existing resetAtToMs for both seconds/milliseconds before comparing future deadlines. Existing manualPreferenceBlocks remains at promotion; reset-first affinity calls mayRebindAffinityForQuota so pool.cacheAffinity retains a healthy bound account until genuine exhaustion. Current config parser preserves accountPoolStrategy through passthrough, so canonical save/reload regression is required. User limits unchanged; previous eligibility D delivered PR4361 with hosted/render pending, reset-first remains independent.

A1 accepted: independent spark/reserve quota scopes use the existing quota strategy consistently for initial selection, preview, affinity and alternates; shared 5h/weekly reset timestamps are not their evidence. Add private `accountPoolStrategyForScope(config, quotaScope)` in routing.ts: normalize the configured Codex strategy, then return quota when reset-first and isIndependentCodexQuotaScope(scope), otherwise the normalized strategy. Use it in pickUnboundStrategyAccount, pickAlternateCodexAccount, previewReusableAffinityAccount and reevaluateAffinityQuota. Shared promotion remains scope-guarded and uses configured normalized strategy. Config remains reset-first, DTO shows configured value and docs explain effective independent-scope fallback. Tests oppose shared reset versus usage order, include scoped cooldown and unchanged shared cursor.

Config decision: retain existing passthrough compatibility rather than add an unrelated disk-validation policy in this carry. Canonical/legacy management writes validate through Codex parser, and all runtime consumers normalize malformed direct config values to quota as before. Explicit invalid parser/API and save/reload tests verify this boundary; no whole-config reset is introduced.

C source audit found threshold=0/cacheAffinity=true could still rebind at100%. Accepted and fixed with early disabled-threshold return before reset-first affinity evaluation; new preview/resolve/all100 fixtures cover both cache settings. Failure recovery stays separate. Local suites NOT RUN; source re-audit and hosted CI pending.
13 changes: 13 additions & 0 deletions devlog/_plan/260912_accounts/031_reset_delivery.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Reset-first carry follows the current pool contract

Adapts #4080 ecf6b4e48a4c2992c296fada2caf6a8132313eaa by Terry Tan. The Codex parser now lives in the existing shared kernel leaf, canonical and legacy settings round-trip the configured strategy, and the GUI offers it only on Codex. Existing runtime priority, manual preference and cache-affinity behavior is preserved. Mixed reset units are normalized before ordering; independent model quota scopes retain existing quota selection.

Regression sources include original reset-first cases plus mixed units, cacheAffinity on/off, scoped fallback/health/shared cursor, canonical and legacy persistence, non-Codex rejection and GUI empty-response normalization. UI hints reflect current cache-affinity and scope semantics. Local tests/build/typecheck/install: NOT RUN. git diff --check is whitespace evidence only; independent source review and hosted final-tip CI/render evidence follow.

Source search: accountPoolStrategy, normalizeAccountPoolStrategy, resetAtToMs, pool/settings, mayRebindAffinityForQuota, manualPreferenceBlocks and all strategy consumers. Existing pool-kernel and routing owners extended; no new dependency or separate pool implementation. Config passthrough behavior preserved deliberately; write routes validate through the Codex-specific parser.

Co-authored-by: Terry Tan <tmy1995hflc@gmail.com>

C source audit found threshold=0/cacheAffinity=true could still rebind at100%. Accepted and fixed with early disabled-threshold return before reset-first affinity evaluation; new preview/resolve/all100 fixtures cover both cache settings. Failure recovery stays separate. Local suites NOT RUN; source re-audit and hosted CI pending.

Independent C re-audit PASS at eddc8c7b08; nonblocking oracle improvement accepted: assert actual alternate b, excluding null as a false recovery result. Hosted/runtime acceptance remains pending.
19 changes: 19 additions & 0 deletions devlog/_plan/260912_accounts/048_history_identity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Bind quota history to credential publication identity

New foundation cycle history-identity, C4 credential metadata, before history and capacity. Current source saveCodexAccountCredential publishes a new generation, while normal refresh CAS also increments generation and preserves replacedAt. Neither generation equality nor a millisecond timestamp alone establishes durable quota-history continuity. Reuse the credential store and its mutation lock; no new store or token-derived fingerprint.

MODIFY src/types/accounts.ts CodexAccountCredentialRecord: optional private quotaHistoryIdentity UUID, not credential material and never projected to API/CLI. MODIFY src/codex/account-store.ts: every explicit save creates a fresh UUID; saveCodexAccountCredentialIfGeneration and commitRefreshedCodexCredentialWithAliases preserve each record's own UUID, including aliases. Deletes retain no old history identity. Existing credential projection excludes metadata automatically.

Add PoolQuotaWriter type in dependency-free src/codex/quota-types.ts:
```ts
export interface PoolQuotaWriter { accountId: string; credentialGeneration: number; historyIdentity: string }
```
Add capturePoolQuotaWriter(accountId, dispatched:{accessToken,chatgptAccountId,generation}) in account-store.ts. Under existing withCredentialMutationLockSync, read record and require exact dispatched credential and generation, live/nondeleted state. For a legacy/malformed missing UUID initialize one once and persist under that lock without changing credential generation; do not mint on normal reads. A mismatch returns undefined. Lock/persistence failures at this optional evidence boundary return undefined, never fail the request. Credentials remain transient and never enter returned proof. Existing valid UUID capture needs only read matching record, no mutation lock or rewrite; legacy slow path rechecks under lock.

Add isPoolQuotaWriterLive(writer): compare current live record's UUID and generation. Add poolQuotaHistoryIdentity(accountId): read valid current UUID only, never initialize or mutate. These separate append admission from retention, which matches UUID across ordinary refresh. Both are narrow production interfaces for the next history layer, not public management capabilities.

Tests extend existing codex-account-store.test.ts: new saves unique; same-millisecond explicit replacement changes UUID; refresh preserves; alias refresh preserves distinct destination identities; stale dispatched access/generation/account cannot capture; legacy initialization stable and does not advance generation; metadata omitted from getCodexAccountCredential/load compatibility projection; delete/recreate invalidates old writer. Local tests/build/typecheck/install NOT RUN. Hosted cumulative history/capacity tip verifies these regression sources. Source security review separate from runtime proof.

Field chain: explicit save/legacy capture creates UUID → existing atomic credential record serialization → existing read with UUID validity checked at history boundary → capture/live/retention helpers → next cycle's auth-context/WHAM/header history admission. All explicit record reconstructions are enumerated: save at161, validation spreads186/234 preserve, refresh279/338 preserve, alias366 preserves its own, deletion387 drops. Source ownership docs updated with private metadata semantics. No credential/token/string values enter docs or log output.

A implementation checks accepted: legacy tag init uses plain persist, preserving both generation and credentialMutationEpoch. UUID validation stays at history boundary; malformed optional metadata never discards usable credentials. Catch read/hardening failures as well as lock/write failures and return no optional proof. Capture excludes the reserved native-main sentinel. If a CAS caller supplies a different upstream account identity, rotate the history UUID instead of treating that as ordinary same-account refresh.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Quota history identity foundation

Adds a private random publication UUID to pool credential records. Explicit saves rotate it, refresh CAS preserves it for the same upstream account, and aliases retain distinct identities. Captured writer proofs require exact dispatched credential generation and access/account pairing; legacy identity initialization occurs under the existing lock without changing the credential generation or mutation epoch. Read/lock/write failure yields no optional proof. Metadata never enters credential-only projection.

Regression sources cover refresh versus same-time replacement, aliases, deletion/recreation, legacy stable initialization, stale capture, malformed metadata, secret-free proof and identity-changing CAS. The latter rotates owner history and does not propagate the new identity into old aliases. No new test file/dependency. Local suites/build/typecheck/install NOT RUN. Source checks are not runtime proof; hosted final cumulative history/capacity tip remains required.

Structural decision: proof type stays in quota-types.ts (type-only), credential record/lock/persistence stay in account-store.ts, future pure history leaf consumes plain evidence. Rejected generation-only retention because ordinary refresh increments it; rejected timestamp identity because publication can share a millisecond. The small foundation is the first ordinary manual-chain PR, then history, then capacity. No merge.
Loading
Loading