Skip to content

feat(codex): classify reset-eligible quota rejection - #866

Merged
Wibias merged 7 commits into
lidge-jun:devfrom
luvs01:feat/657-reset-eligible-exhaustion
Aug 3, 2026
Merged

feat(codex): classify reset-eligible quota rejection#866
Wibias merged 7 commits into
lidge-jun:devfrom
luvs01:feat/657-reset-eligible-exhaustion

Conversation

@luvs01

@luvs01 luvs01 commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Safety boundary

  • reads only a bounded clone of the upstream error response
  • malformed JSON, invalid UTF-8, duplicate keys, oversized, truncated, consumed, or cancelled bodies fail closed and never become reset-credit eligible
  • message text cannot authorize reset-credit eligibility
  • HTTP status remains authoritative: a quota-looking body under 401/403/5xx is not reset eligible
  • the original response remains available for passthrough when no alternate account exists
  • no raw body, account identifier, credential, or token is logged or persisted

Explicit non-goals

This PR deliberately does not implement:

  • automatic reset-credit redemption
  • reset-credit balance or consume calls
  • natural-reset waiting
  • idempotency or single-flight redemption
  • cancellation-bound replay
  • recovery priority configuration
  • GUI or documentation controls

Those remain separate follow-up slices under the maintainer direction in #657.

Compatibility

The existing #584 behavior is preserved: pre-stream 429/402 still permits one bounded alternate-account attempt even when the rejection is generic or unverified. The new semantic classifier has no production call site in this PR; it only establishes the boundary that future irreversible recovery must require.

Verification

  • Bun 1.4.0-canary.1: 119 focused tests passed across quota classification, server auth/retry, bounded-body, and error-fidelity suites
  • bundled Bun 1.3.14: the same 119 focused tests passed
  • TypeScript typecheck passed
  • privacy scan passed
  • git diff --check passed

Refs #657

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of Codex quota and billing responses before streaming begins.
    • Retry behavior now distinguishes verified quota exhaustion from generic rate limits, authentication issues, permissions, and temporary server errors.
    • Only explicitly confirmed exhaustion responses qualify for reset-credit handling, reducing incorrect retry attempts.
    • Added safer handling for malformed, incomplete, oversized, invalid, or interrupted error responses.
    • Preserved response details while evaluating eligibility, including when requests are cancelled.

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Codex pre-stream responses now receive strict structured rejection classification. The classifier fails closed for invalid, unavailable, oversized, consumed, or cancelled bodies. Fatal UTF-8 decoding is supported. The existing 402/429 pool-account retry predicate is now exported. Tests cover schemas, status categories, malformed bodies, cancellation, and response preservation.

Changes

Codex quota retry handling

Layer / File(s) Summary
Fatal UTF-8 body decoding
src/lib/bounded-body.ts
Adds fatalUtf8 support to bounded response decoding for timeout and successful EOF results.
Pre-stream rejection classifier
src/codex/quota-rejection.ts
Adds rejection contracts and asynchronous classification for authentication, permission, transient server, rate-limit, billing/quota, and other responses. Only exact exhaustion codes on HTTP 429 or 402 receive reset-credit eligibility.
Retry export and validation
src/server/responses/core.ts, tests/codex-quota-rejection.test.ts
Exports the existing 402/429 retry predicate. Tests cover exact schemas, ambiguous payloads, malformed and cancelled bodies, status handling, and response preservation.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested reviewers: ingwannu, lidge-jun, wibias

Sequence Diagram(s)

sequenceDiagram
  participant CodexResponse
  participant QuotaClassifier
  participant BoundedBody
  participant RejectionResult
  CodexResponse->>QuotaClassifier: status and response body
  QuotaClassifier->>BoundedBody: clone and decode bounded body
  BoundedBody-->>QuotaClassifier: decoded JSON or read failure
  QuotaClassifier->>RejectionResult: classified rejection and eligibility
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.18% which is insufficient. The required threshold is 80.00%. 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 and concisely describes the main change: classifying reset-eligible Codex quota rejections.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

luvs01 commented Aug 1, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@lidge-jun

Copy link
Copy Markdown
Owner

Pre-merge review result: not merge-ready yet. CI is green and the bounded body handling, privacy posture, and Bun compatibility all check out — but the classifier does not hold the fail-closed boundary the PR description promises:

  1. src/codex/quota-rejection.ts:59 normalizes with trim().toLowerCase(), so near-miss values like " Usage_Limit_Exceeded " or "USAGE_LIMIT_EXCEEDED" classify as reset-credit eligible. Eligibility must be exact, case-sensitive, and allowlisted.
  2. src/codex/quota-rejection.ts:51-63 accepts both root and nested error shapes and both code and type fields, so ambiguous or contradictory payloads (e.g. {error: "opaque", code: "usage_limit_exceeded"}, {error: {code: "unknown", type: "insufficient_quota"}}) are treated as eligible. Unknown or conflicting shapes must fail closed.
  3. tests/codex-quota-rejection.test.ts has no negative coverage for casing/whitespace near-misses or ambiguous/conflicting shapes, so the current suite passes while the boundary leaks.

Please: exact-match allowlisted values within explicitly supported response schemas, reject on conflict, and add the negative tests. This is the semantic foundation for the #657 recovery family, so it is worth getting airtight — happy to re-review quickly once updated.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/server/responses/core.ts`:
- Around line 250-255: Update shouldRetryCodexPoolAccountQuota to be synchronous
and return true only when response.status is 402 or 429, avoiding
classifyCodexPreStreamRejection and any response-body read. Remove the
now-unused classifier import while preserving the existing boolean retry
contract.

In `@tests/codex-quota-rejection.test.ts`:
- Around line 12-13: Extend the test suite in “Codex pre-stream quota rejection
classification” with handleResponses integration coverage for Codex pool
retries. Exercise the reset-eligible 429 and 402 paths in handleResponses,
asserting each retries on an alternate account, and add a non-retryable-status
case asserting the original status and response body are preserved.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3d172e90-de04-4759-a458-eb24d70ac61a

📥 Commits

Reviewing files that changed from the base of the PR and between aae9426 and 08949c0.

📒 Files selected for processing (3)
  • src/codex/quota-rejection.ts
  • src/server/responses/core.ts
  • tests/codex-quota-rejection.test.ts

Comment thread src/server/responses/core.ts Outdated
Comment thread tests/codex-quota-rejection.test.ts
@luvs01

luvs01 commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

All previously requested changes have been applied to the current head (fe44ece), all checks are green, and no review threads remain. When convenient, could you please re-review this revision? Thank you.

@Wibias

Wibias commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

[shipping-github] Verdict: changes-requested

PR: #866 - feat(codex): classify reset-eligible quota rejection
Head: fe44ece on dev (mergeable: MERGEABLE, mergeStateStatus: CLEAN)

Semantic propagation

  • Concepts audited: reset-eligible exhaustion signal (usage_limit_exceeded / insufficient_quota), pre-stream rejection classification, Multi-account failover issue: Session freezes on depleted primary account despite active secondary Pro account #584 pool alternate-account retry predicate, fail-closed bounded body reading
  • Authoritative sources: issue #657 (allowlist requirement), src/codex/quota-rejection.ts (RESET_ELIGIBLE_CODES at line 24), existing error classification src/lib/errors.ts (intentionally broader: text-based), src/server/responses/core.ts (shouldRetryCodexPoolAccountQuota line 249, retry at 1628)
  • Producers and consumers checked: classifyCodexPreStreamRejection has no production call site on this head (tests only); the Multi-account failover issue: Session freezes on depleted primary account despite active secondary Pro account #584 retry stays status-only (402/429) - behavior identical to base, only the export changed; readBoundedResponseBody is pre-existing with its own test file
  • Public/derived representations checked: none new (no API, no serialization, no logging of bodies); codexQuotaOutcomeMeta/header-based quota recording unchanged
  • Material variant partitions checked: code-only, type-only, code+type equal, nested error, root-level, non-string values, unknown values, message-text-only, Retry-After 429, 401/403/5xx/other statuses, malformed/aborted bodies, ambiguous/conflicting schemas
  • Positive and negative assertions checked: positive 6, near-miss 4, ambiguous 4, disagreement 4, message-only, malformed, aborted, status separations, sync retry predicate (4 rows)
  • Unmapped surfaces: none
  • Unproven equivalence assumptions: none
  • Representation mismatches: PR description bullet "connect the bounded classifier to the existing Multi-account failover issue: Session freezes on depleted primary account despite active secondary Pro account #584 retry" does not match the head - fe44ece deliberately un-wired the classifier (retry is status-only again); the classifier is standalone groundwork for Add opt-in rejection-only quota recovery with automatic reset-credit redemption #657
  • Variant coverage gaps: classifier-level negatives for oversized / truncated / consumed bodies exist only indirectly (helper-level in bounded-body.test.ts); the PR claims these fail closed
  • Axis verdict: pass with the description mismatch carried into Spec/Standards

Linked: refs #657 (no closing issues)

Usefulness

Useful and correctly scoped groundwork: this is the maintainer-requested first slice of #657 (semantic classification only, no credit spending, no waiting, no policy), and the classifier is deliberately strict - exact structured codes on 429/402 only, fail-closed on ambiguity, malformed, oversized, consumed, or cancelled bodies. The earlier maintainer findings (case/whitespace normalization, root/nested ambiguity, missing negatives) are all addressed on this head.

Bugs / correctness

  • Method: bug-review.md - Bugbot: n/a (Codex host) - complementary lenses: done (silent_failures, resource_leaks, edge_cases, error propagation, cancellation)
  • Findings: none confirmed. resetEligibleCodeFromResponse clones the response and bails on displaySafe=false/truncated/empty; JSON.parse failures and clone/read throws fail closed; original response stays intact for passthrough (verified: retryCodexPoolOnAlternateAccount cancels the body only when an alternate account exists)
  • Fixed this session: none (review-only run)

Security

  • Scope reviewed: business logic, authz, secrets/config, error mapping (scope: full)
  • Findings: none confirmed. No admission/authz change; bounded 64 KiB / 5 s body reads on a clone; no body text, account identifier, or credential logged; bun run privacy:scan green
  • Fixed this session: none

Spec / standards

Reviews

  • Owners/maintainers: @lidge-jun requested changes on the earlier head (issue comment 5154104384); every requested item (exact matching, ambiguity fail-closed, negative tests) is implemented on fe44ece, and @luvs01 pinged for re-review, but the maintainer has not re-reviewed yet - the authoritative gate still blocks on this
  • Bots (CodeRabbit/Codex): 2/2 threads resolved; latest CodeRabbit review clean; the earlier ask for handleResponses integration coverage is satisfied by existing server-auth.test.ts cases (#584: pre-stream 429 retries once on another eligible pool account and the no-alternate preservation case)

Base / CI

  • Behind/conflicts: head is 294 commits behind current dev tip (56b418187) - no conflicts, but an update from base is needed before merge
  • Required checks: green on head fe44ece - ubuntu, windows, macos, npm-global x3, react-doctor, enforce-target, label, CodeRabbit
  • Local tip compile/tests: bun x tsc --noEmit pass; 105 focused tests pass (quota-rejection, server-auth, bounded-body, error-fidelity); bun run privacy:scan pass

Gate

Ship gate: blocked - wake:trusted_human_feedback_needs_code (maintainer issue comment 5154104384, addressed in code but not yet cleared by a re-review). Not draft, no WIP/do-not-merge.

Bottom line

The code is sound, well-tested, and security-clean: the classifier is fail-closed, #584 behavior is provably unchanged, and CI is green on the head. Three items stand between this PR and merge-ready: (1) @lidge-jun re-review to clear the gate (the author already asked), (2) a one-bullet PR-description correction so the summary matches the unwired classifier on the head, (3) optional but cheap - classifier-level negatives for oversized/truncated/consumed bodies, plus an update from dev before merge.

luvs01 commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

Updated the current revision to d5519db3 on the latest dev and addressed the remaining review items:

The new fork workflow runs are awaiting maintainer approval and contain no jobs yet: Cross-platform CI and React Doctor.

@lidge-jun, when convenient, could you please approve those runs and re-review this revision? Thank you.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/lib/bounded-body.ts (1)

80-87: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document that fatalUtf8: true makes readBoundedResponseBody reject.

With fatal: true, TextDecoder.decode() throws a TypeError on malformed or truncated UTF-8. Both call sites (Line 163 and Line 176) call decodeUtf8 inside return expressions. The throw therefore propagates out of the try block, is re-thrown by the catch at Line 221, and reaches the caller as a rejected promise. The finally block still cancels the reader and releases the lock, so there is no resource leak.

The consequence is a contract change that is not visible from the option name. On the timeout path the caller no longer receives { timedOut: true, displaySafe: false }; it receives a rejection instead. The current consumer src/codex/quota-rejection.ts:177-189 wraps the call in try/catch and fails closed, so present behavior is correct. Future callers can miss this.

Update the option doc so the rejection path is explicit.

📝 Proposed doc clarification
-	/** Reject malformed UTF-8 instead of replacing it. Defaults to false. */
+	/**
+	 * Reject malformed UTF-8 instead of replacing it. Defaults to false.
+	 * When true, decoding throws a `TypeError` for malformed or truncated
+	 * UTF-8, and this function rejects instead of returning a result. The
+	 * reader is still cancelled and released.
+	 */
 	fatalUtf8?: boolean;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/bounded-body.ts` around lines 80 - 87, Update the documentation for
the fatalUtf8 option used by readBoundedResponseBody to explicitly state that
enabling it rejects the promise with a TypeError when malformed or truncated
UTF-8 is encountered, including on the timeout path, rather than returning a
timedOut result. Preserve the existing cleanup and decoding behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/codex/quota-rejection.ts`:
- Around line 209-220: No code change is required: leave
classifyCodexPreStreamRejection and its current bounded-body read unchanged
because alternate-account retry is not yet wired to this classifier.
- Around line 129-137: Rename hasDuplicateJsonObjectKeys to a predicate that
reflects all unsafe outcomes, such as isUnsafeJsonDocument, and update its call
site at the quota-rejection logic accordingly. Preserve the existing return
conditions and fail-closed behavior without inverting or otherwise changing the
predicate.
- Around line 3-5: Make the reset-eligible exhaustion codes single-source by
declaring the literals in a const tuple and deriving
CodexResetEligibleExhaustionCode from that tuple. Remove the duplicate Set
definition and update exactResetEligibleCode to use the resulting
RESET_ELIGIBLE_CODE_SET, preserving its existing behavior.
- Around line 177-183: Extend the tests for the quota-rejection flow around the
response-body guards to directly cover oversized/display-unsafe bodies,
inactivity-truncated bodies, empty bodies, clone failures, and invalid UTF-8,
asserting each is rejected without reset eligibility. Add duplicate-key cases
for root and nested objects, plus conflicting code/type payloads, and verify all
fail closed without triggering the irreversible reset-credit operation.
- Around line 83-85: Replace the number parsing around the scalar scanner with a
module-level sticky regex that matches directly at the current input offset. Set
the regex’s lastIndex to start immediately before exec, then use the match
result and matched length to compute next; preserve the existing SyntaxError and
duplicate:false behavior when no number matches.

---

Outside diff comments:
In `@src/lib/bounded-body.ts`:
- Around line 80-87: Update the documentation for the fatalUtf8 option used by
readBoundedResponseBody to explicitly state that enabling it rejects the promise
with a TypeError when malformed or truncated UTF-8 is encountered, including on
the timeout path, rather than returning a timedOut result. Preserve the existing
cleanup and decoding behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 355d2400-aded-4995-9dc6-79ca84eb4a1e

📥 Commits

Reviewing files that changed from the base of the PR and between fe44ece and d5519db.

📒 Files selected for processing (2)
  • src/codex/quota-rejection.ts
  • src/lib/bounded-body.ts

Comment thread src/codex/quota-rejection.ts Outdated
Comment thread src/codex/quota-rejection.ts Outdated
Comment thread src/codex/quota-rejection.ts Outdated
Comment thread src/codex/quota-rejection.ts Outdated
Comment thread src/codex/quota-rejection.ts
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown

PR quality gates passed

This pull request now targets dev with acceptable ancestry and description.

The title was left unchanged. The pull request has been marked ready for review again.

@github-actions
github-actions Bot marked this pull request as draft August 3, 2026 12:02
@github-actions
github-actions Bot marked this pull request as ready for review August 3, 2026 12:07
@luvs01

luvs01 commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

Latest review follow-up is complete on 454a7c6e.

  • b25b748f makes exhaustion codes single-source, uses an in-place sticky number scan, renames the fail-closed JSON predicate, and adds the empty-body guard test.
  • 454a7c6e documents the fatalUtf8 rejection contract for malformed/truncated UTF-8, timeout-path flushes, and reader cleanup.
  • The five inline review threads have been answered and resolved; inactivity truncation remains covered at the bounded-body helper level without adding a second five-second integration wait or a production test seam.
  • Focused verification: 119/119 on Bun 1.4.0-canary.1 and 119/119 on bundled Bun 1.3.14; typecheck, privacy scan, and git diff --check passed.
  • The classifier still has no production call site, and the existing Multi-account failover issue: Session freezes on depleted primary account despite active secondary Pro account #584 alternate-account retry remains synchronous and status-only.

The PR quality gate is green again and this revision is ready for maintainer re-review.

@Wibias

Wibias commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

[GD] Verdict: changes-requested

PR: #866 - feat(codex): classify reset-eligible quota rejection
Head: 454a7c6 on dev (mergeable: MERGEABLE, mergeStateStatus: UNSTABLE)

Semantic propagation

  • Concepts audited: reset-eligible exhaustion signal (usage_limit_exceeded / insufficient_quota), pre-stream rejection kind taxonomy, #584 pool alternate-account retry predicate, bounded-body fatalUtf8 option, original-response preservation
  • Authoritative sources: issue #657 (exact allow-listed codes, 429 alone insufficient), src/codex/quota-rejection.ts:3 (RESET_ELIGIBLE_CODE_VALUES single source, set derived), src/server/responses/core.ts:249 (shouldRetryCodexPoolAccountQuota), src/lib/bounded-body.ts (fatalUtf8, default false)
  • Producers and consumers checked: classifyCodexPreStreamRejection has no production call site on this head (repo-wide rg: tests only); the #584 retry stays status-only, consumed at core.ts:1687; retryCodexPoolOnAlternateAccount cancels firstResponse.body only when an alternate account is resolved (core.ts:394), so the original response passes through on no-alternate; all existing readBoundedResponseBody call sites (images/web-search/kiro/auth-api/upstream-http-error/server responses) pass no fatalUtf8, so behavior is unchanged
  • Public/derived representations checked: none new (no API, serialization, or logging); the broader text-based classification (src/lib/errors.ts:149, src/adapters/kiro-errors.ts) intentionally stays separate from the exact-code allowlist per #657
  • Material variant partitions checked: root vs nested error, code vs type vs both, 402 vs 429, 401/403/transient/other statuses; transient set 500/502/503/504/520/521/522 matches the #657 table exactly
  • Positive and negative assertions checked: 6 exact shapes; near-miss casing/whitespace x4, ambiguous schema x4, code/type disagreement x4, duplicate keys root+nested, message-only, malformed UTF-8, malformed JSON, empty, oversized, transport-truncated, consumed, aborted, non-eligible statuses x4
  • Unmapped surfaces: none
  • Unproven equivalence assumptions: none
  • Representation mismatches: none
  • Variant coverage gaps: none at classifier level (every claimed fail-closed path has a direct test)
  • Axis verdict: pass

Linked: #657 (refs only; no closing issues)

Usefulness

Useful and correctly scoped: this is the maintainer-requested first slice of #657 (semantic classification only - no credit spending, no waiting, no policy). The classifier is deliberately strict: exact structured codes on HTTP 429/402 only, fail-closed on ambiguity, malformed, oversized, consumed, or cancelled bodies, and status remains authoritative. #584 alternate-account retry is provably unchanged (status-only 402/429), and no irreversible action is reachable from this PR.

Bugs / correctness

  • Method: bug-review.md - Bugbot: n/a (Codex host) - complementary: done (silent_failures, resource_leaks, edge_cases, api_compatibility, error_propagation, retry_idempotency, network_cancellation, boundary_conditions, concurrency_races, resource_lifecycle, parsing_serialization, time_clocks)
  • Findings: none confirmed. The hand-rolled duplicate-key scanner was probed for escape handling, unterminated strings, trailing garbage, number grammar, lastIndex reset, and recursion-depth/stack overflow - every path fails closed; JSON.parse and the scanner must both pass, and the clone read never touches the original response
  • Fixed this session: none (review-only; foreign PR)

Security

  • Scope reviewed: business logic, authz, iac/docker, webhooks/payments, authn, secrets/config, injection (scope: full)
  • Findings: none confirmed. No auth/authz change; body reads bounded to 64 KiB / 5 s on a clone; duplicate keys and ambiguous payloads rejected; no body text, account identifier, or credential logged; bun run privacy:scan passes locally
  • Fixed this session: none

Spec / standards

  • Spec source: issue #657 + PR body
  • Gaps: none. PR claims match the head: classifier standalone with no production call site, #584 unchanged, 119 focused tests verified locally (61 quota/bounded/error-fidelity + 58 server-auth), plus typecheck, privacy scan, and git diff --check all green on bundled Bun 1.3.14 (the 1.4.0-canary.1 run was not repeated here)
  • Standards: src/AGENTS.md followed (Bun-native, no new dependencies, focused tests near the subsystem); no docs-site/ change needed (no user-visible behavior)

Reviews

  • Owners/maintainers: @lidge-jun's requested changes (issue comment 5154104384) are all implemented on this head (exact case-sensitive allowlist, root/nested ambiguity fail-closed, negative tests), but the maintainer re-review is still pending - the authoritative gate blocks on this
  • Bots (CodeRabbit/Codex): 0 unresolved threads (7/7 resolved); latest CodeRabbit review clean; the docstring-coverage pre-merge warning (18.18%) is advisory only, not a repository gate

Base / CI

  • Behind/conflicts: MERGEABLE, but the head is 134 commits behind dev tip e337390 - owner action: update from dev
  • Required checks: enforce-target (pass; one superseded failure on this SHA was replaced by a successful rerun), label (pass), CodeRabbit (pass); Cross-platform CI and React Doctor are action_required on this head (awaiting maintainer approval), which is the UNSTABLE cause
  • Local tip compile/tests: bun run typecheck pass; 119 focused tests pass; bun run privacy:scan pass; git diff --check clean

Simplification (for the PR owner)

Nothing was edited or pushed (foreign PR). Bounded, optional candidates:

  1. tests/codex-quota-rejection.test.ts - normalize mixed indentation (later tests use tabs while the rest of the file uses 2 spaces). Whitespace-only; risk none; validate with git diff --check + the focused tests.
  2. src/lib/bounded-body.ts (readBoundedResponseBody) - hoist const fatal = options.fatalUtf8 === true and pass it to both decodeUtf8 calls instead of repeating the expression. Behavior identical; risk none; validate with bounded-body + quota-rejection tests.

Rejected candidates: narrowing the duplicate-key scan to root/error only, and replacing the hand-rolled scanner with a JSON.parse reviver - both raise correctness risk without maintainability gain; the full-document fail-closed scan is simpler to reason about and already single-sourced after the review rounds.

Gate

Ship gate (review mode): blocked - wake:trusted_human_feedback_needs_code (issue comment 5154104384, addressed in code, awaiting maintainer re-review). Not draft, no WIP/do-not-merge.

Bottom line

Sound, well-tested, security-clean groundwork that matches #657's first slice; this review found no code blockers. Three owner actions stand between this PR and merge-ready: (1) update from latest dev (134 commits behind), (2) get the fork CI approved and green (currently action_required), (3) @lidge-jun re-review to clear the gate. The two simplification candidates above are optional polish.

@Wibias
Wibias force-pushed the feat/657-reset-eligible-exhaustion branch from 454a7c6 to d142f06 Compare August 3, 2026 21:37
@Wibias

Wibias commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Thanks @luvs01 — merging this.

Why it helps: #866 lands the first #657 slice — a strict, fail-closed semantic classifier (src/codex/quota-rejection.ts) so only exact usage_limit_exceeded / insufficient_quota codes on HTTP 429/402 can ever authorize a reset-credit redemption later, while the existing #584 status-only pool retry stays untouched. Rebased onto current dev (d142f068c), full CI matrix green.

@Wibias
Wibias merged commit a088e4b into lidge-jun:dev Aug 3, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants