diff --git a/docs/implementation-status.md b/docs/implementation-status.md index 1b4a929b9..233397cb5 100644 --- a/docs/implementation-status.md +++ b/docs/implementation-status.md @@ -14,9 +14,10 @@ Update this file before each feature commit. | TLS headers and fingerprint | Completed | `1bdd08c` | `cargo test codex_headers_include_desktop_identity_and_turn_state`; `cargo tree \| rg 'reqwest\|rustls'`; full `fmt/test/clippy` before commit | Adds Codex Desktop fingerprint model, exact identity/request headers, and pinned reqwest/rustls client builder. | | Cookie persistence | Completed | `4710926` + `5d3cc6e` + `203270f` | `cargo test cookie_jar_captures_and_replays_account_scoped_cookies`; `cargo test cookie_repository_encrypts_and_replays_account_scoped_cookies`; full `fmt/test/clippy` before `203270f` | Adds account-scoped in-memory Cookie jar and encrypted SQLite Cookie repository; Cookies are replayed only for the same account/domain. Admin-pasted browser Cookie headers are stored encrypted and can be cleared per account. | | Account pool and refresh | Partial | `0f97c5c` + `2f25db8` + `4dc0c9a` + `c2cf7a6` + `636fa79` + `fdb9374` + `3ecd5b6` + `3960a35` + `db6cb98` + `93cfee3` + `6d18d2c` + `a32a53c` + `1d6c301` + `a3b4d2b` | `cargo test account_pool_skips_expired_disabled_banned_and_quota_exhausted_accounts`; `cargo test --test account_pool_scheduling_test`; `cargo test --test account_refresh_test`; `cargo test --test oauth_refresh_test`; `cargo test --test v1_upstream_route_test`; `cargo test --test account_pool_startup_test`; `cargo test --test codex_websocket_test`; Task 5 targeted `cargo test --test v1_upstream_route_test`, `cargo test --test chat_completions_route_test`, `cargo test --test account_pool_scheduling_test`, and WebSocket fallback route tests; Task 7 targeted `cargo test --test admin_accounts_route_test`; auth status/logout targeted `cargo test --test admin_accounts_route_test`; device login targeted `cargo test --test admin_accounts_route_test admin_auth_device`, `cargo test --test oauth_refresh_test`, and `cargo test --test admin_accounts_route_test`; PKCE auth-flow targeted `cargo test --test admin_accounts_route_test admin_auth_`, `cargo test --test oauth_refresh_test`, and `cargo test --test admin_accounts_route_test`; full `fmt/test/clippy` before `db6cb98` | Implements base account status filtering, refresh scheduler semantics, real OpenAI OAuth refresh-token exchange, OpenAI OAuth device-code polling into the shared validated account import path, OpenAI OAuth PKCE authorization-code exchange into the same path, 401-triggered refresh and single retry, max concurrent slots, stale slot cleanup, least-used/round-robin/sticky strategies, tier priority, quota-cache filtering, Cloudflare cooldown skip, request staggering metadata, preferred account selection, exclude IDs, capacity summary, settings-backed pool construction, same-process manual/import/CLI/device/PKCE import-to-pool sync, startup pool snapshots from SQLite with usage-based last-used metadata, in-memory 429 quota cooldown marking, Cloudflare cooldown mutation, pool status mutation for upstream fallback, admin label/status/delete/runtime refresh synchronization, admin reset-usage last-used clearing, runtime pool clearing on logout, shared fallback acquisition for non-streaming Responses, HTTP SSE Responses setup, Chat Completions, and non-history WebSocket handshakes before request body send. `previous_response_id` WebSocket requests remain account-affine on classified failures. Still missing durable release-time slot state and durable quota cooldown persistence because the current account schema has no dedicated cooldown column. | -| Account repository | Completed | `14fe706` + `db6cb98` + `72438c6` + `869b6f8` + `93cfee3` + `a32a53c` | `cargo test --test account_repository_test`; `cargo test --test admin_accounts_route_test`; `cargo test --test admin_accounts_cookies_quota_test`; `cargo fmt --check`; `cargo clippy --all-targets --all-features --locked -- -D warnings`; `cargo test`; full `fmt/test/clippy` before `db6cb98`; full `fmt/test/clippy` before `72438c6`; auth status/logout targeted `cargo test --test admin_accounts_route_test` | Adds encrypted SQLite account token storage, decrypting reads, metadata-only reads for auth status, cursor pagination, full export reads, status/label updates, account deletion, account-wide delete for logout, release-time usage counter persistence, refresh-token-preserving token updates, ChatGPT account/user identity lookup, JWT-claim metadata/token updates that preserve existing labels, quota JSON caching, quota warning snapshot reads, and per-account local usage counter reset. | +| Account repository | Completed | `14fe706` + `db6cb98` + `72438c6` + `869b6f8` + `93cfee3` + `a32a53c` + `b879dd6` | `cargo test --test account_repository_test`; `cargo test --test admin_accounts_route_test`; `cargo test --test admin_accounts_cookies_quota_test`; `cargo fmt --check`; `cargo clippy --all-targets --all-features --locked -- -D warnings`; `cargo test`; full `fmt/test/clippy` before `db6cb98`; full `fmt/test/clippy` before `72438c6`; auth status/logout targeted `cargo test --test admin_accounts_route_test`; quota warnings targeted and full gate before `b879dd6` | Adds encrypted SQLite account token storage, decrypting reads, metadata-only reads for auth status, cursor pagination, full export reads, status/label updates, account deletion, account-wide delete for logout, release-time usage counter persistence, refresh-token-preserving token updates, ChatGPT account/user identity lookup, JWT-claim metadata/token updates that preserve existing labels, quota JSON caching, quota warning snapshot reads, and per-account local usage counter reset. | | Translation | Completed | `eff182e` + `b9c30ba` | `cargo test --test routes_chat_test`; `cargo test --test chat_completions_route_test`; full `cargo fmt --check && cargo test && cargo clippy --all-targets --all-features --locked -- -D warnings` before `b9c30ba` | Adds OpenAI Chat request types, expanded Codex Responses request type, OpenAI Chat to Codex translation for system/developer instructions, multimodal content, tool/function calls, response formats, reasoning effort, service tier, and parallel tool calls. Codex SSE now converts back to OpenAI chat completions and chat chunks with text deltas, reasoning content, tool calls, usage details, and OpenAI-compatible error bodies. | | HTTP routes | Partial | `ab0ad8f` + `3830b21` + `6179d44` + `cfec8ba` + `6341336` + `228febd` + `c2cf7a6` + `e9fdea0` + `ee0ed90` + `fdb9374` + `9ca5c7d` + `b9c30ba` + `350ffbe` + `3ecd5b6` + `3960a35` + `1738f24` + `0b6cc7e` + `f75db60` + `4b19846` + `db6cb98` + `16eb4ed` + `8af350d` + `203270f` + `960bbb2` + `72438c6` + `16938e6` + `869b6f8` + `e1f35e0` + `93cfee3` + `bfe561d` + `cf5ff0b` + `6d18d2c` + `a32a53c` + `1d6c301` + `a3b4d2b` | `cargo test v1_requires_client_api_key_not_admin_cookie`; `cargo test models_route_returns_openai_compatible_codex_model_list`; `cargo test --test admin_settings_route_test`; `cargo test --test model_catalog_test`; `cargo test --test admin_accounts_route_test`; `cargo test --test cli_auth_import_test`; `cargo test --test admin_api_keys_route_test`; `cargo test --test admin_usage_stats_route_test`; `cargo test --test admin_accounts_cookies_quota_test`; `cargo test --test v1_upstream_route_test`; `cargo test --test chat_completions_route_test`; `cargo test --test codex_websocket_test`; targeted HTTP SSE error tests before `bfe561d`; targeted local API key import/export tests before `cf5ff0b`; WebSocket fallback targeted route tests; auth status/logout targeted `cargo test --test admin_accounts_route_test`; device login targeted `cargo test --test admin_accounts_route_test admin_auth_device`, `cargo test --test oauth_refresh_test`, and `cargo test --test admin_accounts_route_test`; PKCE auth-flow targeted `cargo test --test admin_accounts_route_test admin_auth_`, `cargo test --test oauth_refresh_test`, and `cargo test --test admin_accounts_route_test`; full `cargo fmt --check && cargo test && cargo clippy --all-targets --all-features --locked -- -D warnings` before `b9c30ba` and `350ffbe`; Task 5 targeted verification before `3ecd5b6` and `3960a35`; full `fmt/test/clippy` before `1738f24`; full `fmt/test/clippy` plus real-file smoke before `0b6cc7e`; full `fmt/test/clippy` before `f75db60`; full `fmt/test/clippy` before `4b19846`; full `fmt/test/clippy` before `db6cb98`; full `fmt/test/clippy` before `16eb4ed`; full `fmt/test/clippy` before `8af350d`; full `fmt/test/clippy` before `203270f`; full `fmt/test/clippy` before `960bbb2`; full `fmt/test/clippy` before `72438c6`; full `fmt/test/clippy` before `16938e6` | Adds Axum router, health route, `/v1/models`, `/v1/models/catalog`, `/v1/models/{id}`, `/v1/models/{id}/info`, `/debug/models`, `/admin/auth/status`, `/admin/auth/logout`, `/admin/auth/login-start`, `/admin/auth/code-relay`, `/admin/auth/callback`, `/auth/callback`, `/admin/auth/device-login`, `/admin/auth/device-poll/{device_code}`, `/admin/accounts`, `/admin/accounts/quota-warnings`, `/admin/accounts/export`, `/admin/accounts/batch-delete`, `/admin/accounts/batch-status`, `/admin/accounts/health-check`, `/admin/accounts/{id}`, `/admin/accounts/{id}/label`, `/admin/accounts/{id}/status`, `/admin/accounts/{id}/refresh`, `/admin/accounts/{id}/reset-usage`, `/admin/accounts/{id}/quota`, `/admin/accounts/{id}/cookies`, `/admin/accounts/import`, `/admin/accounts/import-cli`, `/admin/api-keys`, `/admin/api-keys/export`, `/admin/api-keys/import`, `/admin/api-keys/batch-delete`, `/admin/api-keys/{id}`, `/admin/api-keys/{id}/label`, `/admin/api-keys/{id}/status`, `/admin/usage-stats`, `/admin/usage-stats/summary`, `/admin/refresh-models`, `/v1/responses` HTTP SSE collection with output item/delta reconstruction plus `output_text` sync for non-streaming clients, default streaming Responses passthrough when `stream` is omitted, WebSocket-backed Responses for `previous_response_id`, explicit non-history WebSocket Responses via `use_websocket`/`useWebSocket`, non-streaming and HTTP SSE setup fallback to another imported account after 429/402/403 account-state failures, WebSocket setup fallback after classified handshake failures when no `previous_response_id` is present, Responses field parity for service tier, tool choice, parallel tool calls, text format, prompt cache key, include, client metadata, reasoning include default, and Codex context headers, plus a dedicated `/v1/chat/completions` route backed by imported Codex accounts with fallback for buffered non-streaming and client-streaming output conversion. `/v1` unauthorized and model errors remain OpenAI-compatible, cached backend model snapshots are used by `/v1/models*` when present, global request-id response headers are preserved, `gpt-5.5` remains the default/test model baseline, and `/admin/settings` is read-only with admin-session auth and lower camelCase envelope. `/admin/auth/status` returns sanitized authenticated state, first account metadata, and pool summary without decrypting or returning tokens. `/admin/auth/logout` clears all account rows and the runtime pool while relying on SQLite foreign-key cascades for usage/cookies. `/admin/auth/login-start` creates a short-lived in-memory PKCE session and returns the OpenAI authorization URL; `/admin/auth/code-relay`, `/admin/auth/callback`, and the registered `/auth/callback` redirect path exchange returned authorization codes and import tokens through the same JWT-claim validated path. `/admin/auth/device-login` starts the OpenAI OAuth device-code flow, and `/admin/auth/device-poll/{device_code}` handles pending/slow_down states or imports returned tokens without returning secrets. `/admin/accounts` reads metadata only and does not decrypt tokens for list views. Manual `POST /admin/accounts` accepts only `token` and/or `refreshToken`, rejects invalid/expired JWTs and missing ChatGPT account claims, derives metadata from JWT claims, ignores caller metadata/status/label, exchanges refresh-token-only inputs through `AppState`'s OpenAI token refresher, preserves or rotates refresh tokens, stores secrets encrypted, synchronizes the runtime account pool, updates existing accounts by `chatgpt_account_id` + `chatgpt_user_id`, and never echoes tokens. `/admin/accounts/quota-warnings` returns active warning/critical quota windows computed from cached SQLite quota JSON without contacting upstream. `/admin/accounts/import` accepts native and Sub2API OpenAI OAuth account exports, returns `sourceFormat`, and ignores proxy-only metadata. `/admin/accounts/import-cli` reads Codex CLI `auth.json` from `$CODEX_HOME` or an explicit admin fixture path, uses the same validated JWT-claim account import path as manual add, ignores caller metadata, and returns only sanitized import counts. `/admin/accounts/export` returns native or Sub2API OpenAI OAuth exports without proxy fields. `/admin/accounts/{id}/label`, `/status`, `/refresh`, `/reset-usage`, `/quota`, delete, batch-delete, batch-status, and `/admin/accounts/health-check` mutate or inspect SQLite plus runtime account pool without returning secrets; health/quota call Codex backend usage endpoints through imported account tokens and classify invalid/quota/banned/Cloudflare responses into account state or cooldown. `/admin/accounts/{id}/cookies` stores/reads/deletes encrypted per-account browser cookies. `/admin/api-keys/{id}/label`, `/status`, delete, and batch-delete mutate local client key rows used by `/v1` auth; `/admin/api-keys/export` returns metadata only without plaintext/keyHash/pepper, and `/admin/api-keys/import` rotates metadata into new local keys with plaintext returned once. These are local auth utilities, not TS provider key pool parity. `/admin/refresh-models` fetches backend model lists through imported accounts only, stores plan snapshots, and syncs runtime model-plan allowlists. Still missing settings mutation/persistence, diagnostics, and live Chat streaming transform. | +| Admin quota warnings | Completed | `b879dd6` | `cargo test --test admin_accounts_cookies_quota_test quota_warnings`; `cargo test --test admin_accounts_cookies_quota_test`; `cargo fmt --check`; `cargo test`; `cargo clippy --all-targets --all-features --locked -- -D warnings` | Adds `/admin/accounts/quota-warnings`, backed by cached SQLite quota snapshots and configured warning thresholds. The route is admin-session gated, returns lower camelCase admin envelopes, and does not call upstream Codex while listing active warnings. | | Admin/frontend response contract | Completed | `1c34ea7` + `b0c10f2` | `cargo test admin_envelope_serializes_lower_camel_case_request_id`; `cargo test admin_logs_reject_missing_admin_session_cookie`; `cargo test v1_response_has_request_id_header_without_admin_body_field`; full `fmt/test/clippy` before commit | Adds reusable admin envelopes with body codes, lower camelCase JSON, paginated list shape, requestId bodies, admin session cookie enforcement, and keeps `/v1/*` OpenAI-compatible. | | HTTP auth boundary | Completed | `cec4607` + `e9fdea0` | `cargo test --test http_auth_test`; `cargo test --test routes_responses_test`; `cargo test --test admin_api_keys_route_test`; `cargo test --test admin_logs_route_test`; `cargo fmt --check`; `cargo clippy --all-targets --all-features --locked -- -D warnings`; `cargo test` | Adds a real `src/http/auth.rs` boundary for client API key and admin session cookie parsing. `/v1/*` accepts only enabled local `Bearer cpr_...` client API keys verified from SQLite, admin session parsing ignores client API keys, and route handlers no longer own ad hoc credential parsing. | | Model catalog | Partial | `6341336` + `1738f24` + `f75db60` + `4b19846` | `cargo test --test model_catalog_test`; `cargo test model_catalog_route_returns_codex_metadata_without_alias_entries`; `cargo test --test storage_schema_test`; `cargo test --test routes_responses_test model_catalog_route_returns_cached_backend_models`; `cargo test --test admin_models_route_test`; full `fmt/test/clippy` before `1738f24`; full `fmt/test/clippy` before `f75db60`; full `fmt/test/clippy` before `4b19846` | Adds a native static Codex model catalog with `gpt-5.5` default, configured aliases, reasoning/service-tier suffix parsing including `none` and `minimal`, OpenAI-compatible `/v1/models`, extended catalog/detail/info routes, debug summary, SQLite-backed backend model snapshots by plan, cached backend catalog merge, model-to-plan allowlist derivation, and an admin refresh route that probes Codex model endpoints with one imported account per plan and syncs the runtime account-pool allowlist. Still missing full model metadata parity. | diff --git a/docs/superpowers/plans/2026-06-11-codex-proxy-rs.md b/docs/superpowers/plans/2026-06-11-codex-proxy-rs.md index 86a58ee43..3b5dedd4e 100644 --- a/docs/superpowers/plans/2026-06-11-codex-proxy-rs.md +++ b/docs/superpowers/plans/2026-06-11-codex-proxy-rs.md @@ -3016,9 +3016,9 @@ This pass re-read the TypeScript routes and core modules under `/home/zyy/Codes/ - [ ] Old `/admin/*` settings mutations used the proxy API key as a write gate. Rust must use admin sessions only. - [ ] Old refresh fallback could be dangerous for one-time refresh tokens if retried after a mid-flight failure. Rust must keep the one-time RT preservation rule and retry only when the request definitely did not reach the server. -- [ ] Old settings exposed proxy and provider knobs that are out of scope. Rust config and API must not keep dead settings as no-op compatibility fields. -- [ ] Old route responses mix multiple body shapes. Rust must keep `/v1/*` OpenAI-compatible and `/admin/*` lower camelCase `code/message/data/requestId`. -- [ ] Empty placeholder modules are not acceptable. A module either owns tested behavior or is removed from the target structure with a documented reason. +- [x] Old settings exposed proxy and provider knobs that are out of scope. Rust config and API keep proxy URL, provider, Ollama, OpenAI official key, proxy API key, and Electron/self-update fields out of the retained settings surface. +- [x] Old route responses mix multiple body shapes. Rust keeps `/v1/*` OpenAI-compatible and `/admin/*` lower camelCase `code/message/data/requestId`, backed by dedicated API contract tests. +- [x] Empty placeholder modules are not acceptable. Current module roots either expose real submodules or owned behavior; no empty Rust source modules remain in `src/`. --- diff --git a/docs/superpowers/plans/2026-06-12-openai-gpt-codex-parity.md b/docs/superpowers/plans/2026-06-12-openai-gpt-codex-parity.md index a2aae81f5..1a22b0e49 100644 --- a/docs/superpowers/plans/2026-06-12-openai-gpt-codex-parity.md +++ b/docs/superpowers/plans/2026-06-12-openai-gpt-codex-parity.md @@ -10,6 +10,8 @@ **Checkpoint 2026-06-12:** Commit `b9c30ba` completed Tasks 1-3 for the in-scope OpenAI GPT/Codex path: Chat Completions route/translation/output, Responses request field parity, default Responses streaming, Codex context headers, and local-only WebSocket flag serialization cleanup. Commit `350ffbe` completed Task 4: `previous_response_id` requests use WebSocket `response.create` and return SSE-compatible output. Commit `3ecd5b6` partially completed Task 5 for non-streaming `/v1/responses`: 429/402/403 account-state classification and fallback retry across imported accounts. Commit `3960a35` extends the same fallback path to HTTP SSE Responses setup and Chat Completions. Commit `6d18d2c` completes Task 5 policy for WebSocket-backed Responses: handshake upstream errors are classified before request body send, non-history WebSocket requests may fallback accounts, successful handshakes capture rate-limit headers, and `previous_response_id` requests remain account-affine for streaming and non-streaming clients. Commit `1738f24` adds Task 6 cache groundwork: persisted backend model snapshots and cached `/v1/models*` reads. Commit `0b6cc7e` adds Task 7 import compatibility for Sub2API OpenAI OAuth exports and marks the detected source format while ignoring proxy-only fields. Commit `f75db60` adds `/admin/refresh-models` backed by imported accounts. Commit `4b19846` syncs refreshed model-plan allowlists into the runtime account pool. Commit `db6cb98` adds admin account label/status/delete mutations with runtime pool synchronization. Commit `16eb4ed` adds batch delete/status mutations. Commit `8af350d` adds local client API key status/delete mutations. Commit `203270f` adds encrypted account Cookie get/set/delete. Commit `960bbb2` adds local client API key label and batch-delete mutations. Commit `72438c6` adds native and Sub2API account export. Commit `16938e6` adds manual account creation for Codex OAuth tokens. Commit `869b6f8` narrows `POST /admin/accounts` to TS-like `token`/`refreshToken` import semantics for OpenAI GPT/Codex accounts. Commit `e1f35e0` adds deterministic Codex CLI `auth.json` import through the same validated JWT-claim path. Commit `93cfee3` adds admin health-check, per-account refresh, reset-usage, and quota routes for imported Codex accounts. Commit `bfe561d` maps HTTP SSE terminal failures to OpenAI-compatible upstream errors for non-streaming clients while preserving streaming passthrough. Commit `cf5ff0b` adds Rust-local client API key metadata export/import with target-local key rotation. Commit `a32a53c` adds admin-session-gated `/admin/auth/status` and `/admin/auth/logout`, returning sanitized account/pool state and clearing SQLite accounts plus the runtime pool without token exposure. Commit `1d6c301` adds admin-session-gated `/admin/auth/device-login` and `/admin/auth/device-poll/{device_code}` backed by the OpenAI OAuth device-code flow and shared validated account import path. Commit `a3b4d2b` adds `/admin/auth/login-start`, `/admin/auth/code-relay`, `/admin/auth/callback`, and the registered `/auth/callback` redirect path, with in-memory PKCE sessions, OpenAI authorization-code exchange, and shared validated account import. +**Checkpoint 2026-06-13:** Commit `b879dd6` adds admin-session-gated `/admin/accounts/quota-warnings`, computed from cached SQLite quota snapshots and configured warning thresholds without calling the upstream Codex backend. + **Scoped HTTP SSE error update:** Non-WebSocket `/v1/responses` HTTP SSE collection now detects upstream `event: error` and `event: response.failed` terminal frames. Non-streaming clients receive a `502` OpenAI-compatible `upstream_error` body with the upstream message, while streaming clients keep passthrough SSE frames and record the lifecycle event as an upstream SSE failure. --- @@ -198,7 +200,7 @@ Immediate priority after this audit: - Modify: `docs/implementation-status.md` - Modify: `README.md` if route behavior changes -- [ ] Run: `cargo fmt --check` -- [ ] Run: `cargo test` -- [ ] Run: `cargo clippy --all-targets --all-features --locked -- -D warnings` -- [ ] Update implementation status with completed parity items and any intentionally omitted non-goals. +- [x] Run: `cargo fmt --check` +- [x] Run: `cargo test` +- [x] Run: `cargo clippy --all-targets --all-features --locked -- -D warnings` +- [x] Update implementation status with completed parity items and any intentionally omitted non-goals. diff --git a/docs/superpowers/plans/2026-06-13-utils-module-migration.md b/docs/superpowers/plans/2026-06-13-utils-module-migration.md index 80e57c43a..9ad4dbdaf 100644 --- a/docs/superpowers/plans/2026-06-13-utils-module-migration.md +++ b/docs/superpowers/plans/2026-06-13-utils-module-migration.md @@ -34,7 +34,7 @@ The document should state that `utils` may contain `pagination`, `json`, and `cr - Delete: `src/pagination.rs` - Delete: `src/crypto.rs` -- [ ] **Step 1: Add the utils module root** +- [x] **Step 1: Add the utils module root** ```rust pub mod crypto; @@ -42,15 +42,15 @@ pub mod json; pub mod pagination; ``` -- [ ] **Step 2: Move pagination helpers** +- [x] **Step 2: Move pagination helpers** Move `Page`, `encode_cursor`, `decode_cursor`, and `clamp_limit` into `src/utils/pagination.rs` unchanged. -- [ ] **Step 3: Move crypto helpers** +- [x] **Step 3: Move crypto helpers** Move `CryptoError`, `CryptoResult`, and `SecretBox` into `src/utils/crypto.rs` unchanged. -- [ ] **Step 4: Add JSON string helpers** +- [x] **Step 4: Add JSON string helpers** ```rust use serde_json::Value; @@ -72,7 +72,7 @@ pub fn string_at(value: &Value, path: &[&str]) -> Option { } ``` -- [ ] **Step 5: Expose `utils` from the library** +- [x] **Step 5: Expose `utils` from the library** ```rust pub mod utils; @@ -93,17 +93,17 @@ Remove the old top-level `pub mod crypto;` and `pub mod pagination;` declaration - Modify: `tests/*.rs` - Modify: `tests/common/*.rs` -- [ ] **Step 1: Update source imports** +- [x] **Step 1: Update source imports** Use `crate::utils::crypto::{CryptoError, SecretBox}` and `crate::utils::pagination::{clamp_limit, decode_cursor, encode_cursor, Page}`. -- [ ] **Step 2: Update integration test imports** +- [x] **Step 2: Update integration test imports** Use `codex_proxy_rs::utils::crypto::SecretBox` and `codex_proxy_rs::utils::pagination::Page`. -- [ ] **Step 3: Remove duplicate JSON helper functions** +- [x] **Step 3: Remove duplicate JSON helper functions** Import `crate::utils::json::first_string` in `src/service/api_key_service.rs` and `src/http/admin/accounts.rs`, then delete the local `first_string` and `string_at` @@ -114,7 +114,7 @@ definitions. **Files:** - No source edits after this task unless verification fails. -- [ ] **Step 1: Format** +- [x] **Step 1: Format** Run: @@ -122,7 +122,7 @@ Run: cargo fmt ``` -- [ ] **Step 2: Run focused tests** +- [x] **Step 2: Run focused tests** Run: @@ -130,7 +130,7 @@ Run: cargo test --test crypto_test --test account_repository_test --test admin_accounts_import_export_test --test admin_api_keys_route_test ``` -- [ ] **Step 3: Run full gate** +- [x] **Step 3: Run full gate** Run: