Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
56 changes: 56 additions & 0 deletions devlog/_plan/260905_main_quota_guard/000_plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Main-account quota protection and Reserve compatibility

## Loop specification

- Archetype: spec-satisfaction repair; HOTL, bound checkout 8841.
- Trigger: owner requests a 99% main-account hard-lock switch beside Ultra Fast and an investigation/patch for using other models alongside Luna reserve.
- Goal: stop new main-account admissions at observed 99% usage while keeping unrelated routes available, with explicit opt-in consequences and truthful Reserve compatibility.
- Non-goals: upstream entitlement bypass, invented ordinary-usage recovery, quota reset redemption, modifying live port 10100, releases, replacing Codex binaries, or editing the reference corpus.
- Verifier: exact-head GitHub CI, TypeScript check, existing GUI build/lint, isolated browser interaction and screenshots. No local test suites, including focused suites or test:changed. User explicitly authorizes no-verify pushes and admin merges after green CI/review.
- Stop: every registered criterion evidenced and stack merged bottom-up; otherwise report actual missing external authority, not completion.
- Memory: this unit plus the session-bound goalplan/ledger.
- Resources: existing local tools and GitHub credentials; no purchases; 4-hour reassessment checkpoint. Model and effort inherited for all lanes. Main reclaims a packet after two distinct worker failures; delegation changes are P amendments.
- Terminal outcomes: DONE, NOOP with evidence, BLOCKED/NEEDS_HUMAN for a real external prerequisite, UNSAFE for an entitlement bypass, BUDGET_EXHAUSTED only at the stated bound.

## Baseline and ownership

Base `d6b457462` matches fetched `origin/dev`. Checkout began clean/detached and was adopted in place as `codex/main-account-99-hard-lock`.
Installed locked root/GUI dependencies without changing manifests. Initial typecheck lacked bun-types; after frozen install, `bun run typecheck` exited 0. No tests executed.

```text
src/types/config.ts + src/config.ts persisted opt-in
src/codex/quota.ts + auth-api.ts observed quota and physical identity
src/codex/account-usability.ts Pool exclusion
src/codex/auth-context.ts final native-main admission
src/server/management/config-routes.ts settings transaction/DTO
gui/src/pages/codex-set-multiauth.tsx existing advanced settings placement
gui/src/components/ switch/dialog/main-card status
tests/codex-integration/ + tests/config/ CI-only behavioral regression
```

Reuse existing config mutation/rollback, quota parsing, account identity reconciliation, native dialogs and UI tokens. Do not add a framework, second settings API, or credential store.

## Dependency-ordered work phases

1. wp0: source-grounded docs-only roadmap and independent audit; lock before production edits.
2. wp1 / `010_policy.md`: main quota protection contracts, admission and management, with regression coverage. Bottom PR targets dev and works without the UI layer.
3. wp2 / `020_settings.md`: switch, confirmation, main-card state and supported Reserve compatibility documentation; depends on the policy contract. Upper PR targets the bottom branch.
4. wp3 / `030_delivery.md`: exact-head review/CI and bottom-up authorized admin merge, followed by fetched ancestry and closure evidence.

The Reserve client gate is a separate feasibility decision, not permission to misrepresent server state. If source establishes a safe OCX-only compatibility patch, concretize it as a P amendment before writing. If it requires modifying the installed Desktop client or publishing to an unspecified upstream repository, record the boundary and ask for that specific decision after completing in-scope work; do not claim same-picker coexistence.

## Acceptance

- Off/absent flag preserves current routing. Enabled flag uses the 5h/short window when present, otherwise weekly, otherwise monthly-only usage; it blocks at >=99 on that selected window. Other windows cannot trigger this local policy. Unknown data is not invented as 0 or 100. Owner steering is recorded in 013.
- Main exclusion cannot prevent usage refresh or profile recovery. Explicit main and Direct paths cannot evade a measured block; unrelated caller credentials cannot inherit main's quota.
- Observations are identity-bound; account changes and restart cannot attach another account's cached reading. Only a fresh valid lower observation releases this policy, not clock-only expiry, pause/cooldown/reauth. The existing minute sweep refreshes blocked main usage without inference or reset credits.
- UI distinguishes enabled from currently blocked. Cancel/Escape do not save; save errors preserve actual server state; success requires explicit acknowledgment. Main status remains visible outside Advanced.
- Do not claim 1% is reserved: parallel/in-flight/direct-to-upstream use can reach 100 before observation. Luna reserve cannot be used while this policy blocks the main account.
- Keep server Reserve grants and `ordinary_usage_allowed` unchanged.
- Every merge requires reviewed exact-head CI and an origin/dev ancestor check.

## Continuity

wp0 roadmap build: independent audit PASS after three accepted amendments (outbound guard reachability, six-hour durability, effective workspace matching). Baseline root typecheck, GUI build and GUI i18n lint passed. No production edits or local suites.

Next wp1 P: reread 010 against current tree, name exact worker API boundaries, include the discovered Direct sidecar header path in `src/providers/openai-sidecar.ts`, then independently audit before building. Reserve Desktop investigation remains read-only and may add a later bounded compatibility cycle if evidence supports it.
47 changes: 47 additions & 0 deletions devlog/_plan/260905_main_quota_guard/001_source_findings.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Source findings

## Why the existing threshold is insufficient

`src/codex/auth-context.ts:67` reads `autoSwitchThreshold` for request-owned main pins. It is a selection preference, not a refusal. `src/codex/routing.ts` permits terminal main fallback and scores unknown usage as 101; it cannot be reused as a 99% predicate. A short-only 99% observation still scores unknown.

`src/codex/native-main-admission.ts` covers credential and management claims, not only billable work. Blocking it would prevent the quota refresh needed to recover.

`src/codex/account-lifecycle.ts:63` reconciles the stable `__main__` alias with physical identity. `src/codex/auth-api.ts:866` already owns identity-checked WHAM reads. Request-owned native bearers must not introduce new physical-main reads.

## Settings/UI

`gui/src/pages/codex-set-multiauth.tsx:197` places account picker, request-user-input and Ultra Fast under `advancedExtras`. `src/server/management/config-routes.ts:383` owns partial PUT validation, persistence and rollback. The new setting must return its confirmed value; do not inherit Ultra Fast's missing PUT acknowledgment fallback.

`gui/src/components/codex-account-pool-main-card.tsx` owns persistent main status, `gui/src/hooks/useCodexAccountPool.ts` owns its DTO, and native `<dialog>` patterns already exist in `codex-account-switch-modal.tsx`.

## Reference Codex TUI, inspected 2026-09-05

Reference prefix: local `121_openai-codex/codex-rs/tui/src/chatwidget/` beneath the user's Codex research corpus; not this repository's runtime.

- `backend_banners.rs:61`: picker restriction is current model `gpt-reserve` plus missing ordinary-usage recovery, not a numeric 100% comparison.
- `model_popups.rs:82,199`: both picker entry points replace all catalog choices with the Reserve-only picker.
- `backend_banners.rs:307`: recovery requires a full identity-validated backend response with `ordinary_usage_allowed` and no remaining blocking state.
- Consequently, catalog injection alone cannot fix that TUI restriction. Exposing other native models by falsifying recovery would misrepresent upstream authorization.
- Desktop behavior still requires separate source evidence; TUI evidence is not Desktop proof.

## Reserve follow-up

`src/codex/inject.ts:191,319` already supports the explicit `codexDesktopAuthless` loopback mode, which uses a custom provider with `requires_openai_auth=false`. Reference app-server `model-provider/src/provider.rs:401` then reports no native account requirement. Whether Desktop's Reserve picker follows this state remains unverified.
`src/router.ts:633` accepts an explicitly configured `main/gpt-reserve` namespace, but routing acceptance is not Reserve entitlement. Static native listing omits Reserve, and unknown account-native discovery currently requires supported_in_api=true, unlike the existing Reserve-shaped test fixture. No live Reserve inference or Desktop coexistence has been proven. Do not synthesize availability or change upstream recovery flags; validate this seam before planning any compatibility implementation.

## Installed Desktop source, 26.901.22334 / build 7746

Read the existing application archive without extraction, installation, application writes or restart. Member offsets below are zero-based UTF-8 bytes, not source line numbers.

- `webview/assets/app-initial-f1c3ba37268a.js`, offset4132166: Reserve eligibility rejects an auth method other than `chatgpt`, besides feature/plan/identity/version checks.
- Same member, offset4133005: active Reserve requires ordinary `rate_limit.allowed=false`, a `gpt-reserve` additional limit with `allowed=true`, and `luna_reserve` banner.
- Same member, offset4451408: account/auth projection reads `account` plus `requiresOpenaiAuth` from app-server. The reference provider's `account_state` reports no native account when `requires_openai_auth=false`.
- `webview/assets/app-primary-b1300cb15eed.js`, offset7352039: active Reserve replaces the whole picker list with the single Reserve row; it has no per-provider exception.

Source conclusion: an effective authless custom provider disables this native Reserve-only picker gate, AND disables Desktop automatic Reserve handling. No installed-client patch is necessary for that particular gate. Explicit Reserve plus routed-model coexistence still needs independently verified catalog/routing/quota compatibility. No live Reserve-entitled session was used; do not label these source checks as live success.

## Necessity and limits

Do nothing/configure-only fails because the existing threshold can return to main. Reuse the existing eligibility and native-auth resolution owners. A small policy leaf is justified to share raw-window/identity logic between routing and the status DTO without importing management or Lab into core paths.

The feature is local request admission, not a reservation of the remaining quota. Known bypass: requests already admitted or sent directly to OpenAI. Final upstream authority remains OpenAI; no client code can promise that a displayed 99 never advances to 100.
11 changes: 11 additions & 0 deletions devlog/_plan/260905_main_quota_guard/002_audit_synthesis.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Roadmap audit synthesis

Independent reviewer Kuhn returned FAIL with three high blockers. Accepted all three; no rebuttal and no production edits.

1. Outbound enforcement: the plan described intent but the actual materialization APIs lacked config. Added explicit options.config threading through core/compact, post-await recheck and race tests. The old unused assertion is explicitly insufficient. Follow-up source search also found legacy `headersForCodexAuthContext` paths in core/compact/ws-bridge; implementation must carry the same config or a live policy closure there rather than treating them as harmless wrappers.
2. Durable evidence: the old cache expires after six hours, contradicting missing-reset retention. Added independent identity-tagged `mainPolicyQuota` envelope member, retained across rotation TTL and unrelated persistence, with one shared partial merge rule and restart tests.
3. Workspace identity: credential equality alone does not imply the selected workspace matches. Added both-token-and-selected-identity matching, conflicting-header exclusion, zero-new-auth-read tests and explicit unmatched-keyring limitation.

Cross-blocker consistency: final materialization reads the same current policy/status getter; its retained evidence is identity-bound and never recovered by trusting an unsigned caller claim. Maintenance reads remain allowed. Legacy routing reads retain their original semantics.

Baseline checks actually observed by main: root typecheck exit0; GUI build exit0 (existing large-chunk advisory); GUI lint:i18n exit0. No local suites. Source-level findings refer to base d6b457462.
Loading
Loading