Skip to content

fix(proxy): ignore stale quota cooldowns - #1323

Merged
murdore merged 1 commit into
releasefrom
fix/proxy-stale-quota-cooldowns
Aug 14, 2026
Merged

murdore merged 1 commit into
releasefrom
fix/proxy-stale-quota-cooldowns

Conversation

@murdore

@murdore murdore commented Aug 12, 2026 •

Copy link
Copy Markdown
Contributor

Root cause

The worker rehydrated account-quotas.json after a restart, then treated persisted rejected quota statuses as current upstream evidence. This could create fresh cooldowns from stale snapshots without sending a request. In the observed incident, the configured NeuroLink account snapshot was five days old and was immediately cooled despite having current availability.

Changes

  • Startup quota hydration no longer creates or clears account cooldowns. Only persisted cooldowns and fresh upstream headers affect admission state.
  • Quota snapshots older than 15 minutes are retained for diagnostics but are excluded from routing, saturation, and usability decisions.
  • Routing evidence now marks such records with quotaStale: true; offline analysis accepts historical records that do not contain the new field.
  • Parse Anthropic unified-overage-in-use; when paired with overage-status: allowed, it keeps the account eligible even when the fallback header is absent.

Validation

  • pnpm exec vitest run test/proxyReliabilityHardening.test.ts test/proxyAnalysis.test.ts test/proxyUpdaterFallback.test.ts test/proxyUsageStatsPersistence.test.ts (163 passing)
  • pnpm run test:proxy-limit-headers (18 passing)
  • pnpm exec prettier --check ...
  • pnpm exec tsc --noEmit
  • git diff --check

No live proxy files, processes, configuration, or traffic were touched for this PR.

Summary by CodeRabbit

  • Bug Fixes

    • Improved quota handling when paid overage is actively in use.
    • Prevented outdated quota snapshots from incorrectly blocking account routing.
    • Preserved active cooldowns when restoring persisted quota information.
    • Improved compatibility with legacy quota data.
    • Ensured invalid quota freshness values do not affect routing decisions.
  • Improvements

    • Added quota freshness indicators and age information to routing decisions.
    • More accurately reports account availability, utilization, and saturation using current quota data.

Copilot AI lite review requested due to automatic review settings August 12, 2026 19:26
@github-actions

github-actions Bot commented Aug 12, 2026 •

Copy link
Copy Markdown
Contributor

✅ Single Commit Policy - COMPLIANT

Status: Policy requirements met • 1 commit • Valid format • Ready for merge

📊 View validation details

📝 Commit Details

  • Hash: 6d114b7bd6b480ca6b9cc853f56e7a578324e4f5
  • Message: fix(proxy): ignore stale quota cooldowns
  • Author: Sachin Sharma

✅ Validation Results

  • Single commit requirement met
  • No merge commits in branch
  • Semantic commit message format verified
  • Ready for squash merge to release branch

🤖 Automated validation by NeuroLink Single Commit Enforcement

@coderabbitai

coderabbitai Bot commented Aug 12, 2026 •

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 9bae9d1e-af98-4f1e-a9a3-e6fedc91a8a9

📥 Commits

Reviewing files that changed from the base of the PR and between 4bd609a and 6d114b7.

📒 Files selected for processing (3)
  • src/lib/proxy/accountQuota.ts
  • src/lib/server/routes/claudeProxyRoutes.ts
  • src/lib/types/proxy.ts

📝 Walkthrough

Walkthrough

The change adds active overage parsing and availability handling. Persisted quota snapshots older than 15 minutes no longer affect cooldown admission or active routing evidence. Routing candidates now expose normalized quota staleness.

Changes

Quota routing reliability

Layer / File(s) Summary
Active overage signal
src/lib/proxy/accountQuota.ts, src/lib/types/proxy.ts, test/proxyReliabilityHardening.test.ts
Quota parsing records overageInUse. Explicit active overage makes overage available when allowed. Tests cover headers without a fallback header.
Stale quota admission
src/lib/server/routes/claudeProxyRoutes.ts, test/proxyReliabilityHardening.test.ts
Persisted quota snapshots use a 15-minute freshness threshold. Startup seeding no longer changes cooldown state. Tests verify existing cooldown preservation and stale snapshot behavior.
Stale routing evidence
src/lib/server/routes/claudeProxyRoutes.ts, src/lib/proxy/proxyAnalysis.ts, src/lib/types/proxy.ts
Routing ignores stale quota for active availability, utilization, and saturation. Candidates and metrics expose normalized quota staleness and age.

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

Sequence Diagram(s)

sequenceDiagram
  participant Startup
  participant PersistedQuota
  participant CooldownState
  participant RoutingMetrics
  participant RoutingCandidate

  Startup->>PersistedQuota: load quota snapshot
  Startup->>PersistedQuota: calculate snapshot age
  Startup->>CooldownState: preserve active cooldown state
  RoutingMetrics->>RoutingCandidate: include quotaStale and quota age
Loading

Possibly related PRs

Suggested reviewers: tara-ag

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the primary change: preventing stale persisted quota data from creating cooldowns during proxy startup.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/proxy-stale-quota-cooldowns

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

🤖 AI Review & Build Compliance ✅

Status: AI analysis complete • Build rules validated • Ready for review

📊 View detailed analysis results

🛡️ Analysis Complete

  • ✅ Security scan (vulnerabilities, API keys)
  • ✅ TypeScript safety & code quality
  • ✅ Error handling & best practices
  • ✅ Build rule enforcement validated
  • ✅ Commit format & compliance checks

📋 Ready for Merge When

  • All CI checks passing
  • Manual review approved
  • Any AI-flagged issues resolved

🤖 AI analysis complete - check individual code comments for specific feedback

@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: 1

🤖 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/lib/server/routes/claudeProxyRoutes.ts`:
- Around line 987-993: Update the quota freshness logic around quotaLastUpdated,
quotaAgeMs, and quotaStale so any finite persisted timestamp greater than now is
treated as stale rather than clamped to zero age; preserve the existing
freshness threshold for non-future timestamps, and add coverage for a future
persisted timestamp.
🪄 Autofix

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: CHILL

Plan: Pro Plus

Run ID: 75e560fb-4303-47bc-8bb7-5393c1a63d1c

📥 Commits

Reviewing files that changed from the base of the PR and between fba230b and 4bd609a.

📒 Files selected for processing (5)
  • src/lib/proxy/accountQuota.ts
  • src/lib/proxy/proxyAnalysis.ts
  • src/lib/server/routes/claudeProxyRoutes.ts
  • src/lib/types/proxy.ts
  • test/proxyReliabilityHardening.test.ts

Comment on lines +987 to +993
const quotaLastUpdated =
q && Number.isFinite(q.lastUpdated) ? q.lastUpdated : null;
const quotaAgeMs =
quotaLastUpdated === null ? null : Math.max(0, now - quotaLastUpdated);
const quotaStale =
quotaAgeMs !== null && quotaAgeMs > QUOTA_SNAPSHOT_FRESHNESS_MS;
const routingQuota = quotaStale ? undefined : q;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Treat future persisted timestamps as stale.

Line 990 clamps a future lastUpdated value to zero age. A snapshot saved by a clock ahead of the current process remains fresh for up to its future offset plus 15 minutes. Its rejected status can then make an account unusable after restart.

Mark quotaLastUpdated > now as stale. Add a test with a future persisted timestamp.

Proposed fix
   const quotaAgeMs =
     quotaLastUpdated === null ? null : Math.max(0, now - quotaLastUpdated);
   const quotaStale =
-    quotaAgeMs !== null && quotaAgeMs > QUOTA_SNAPSHOT_FRESHNESS_MS;
+    quotaLastUpdated !== null &&
+    (quotaLastUpdated > now ||
+      quotaAgeMs! > QUOTA_SNAPSHOT_FRESHNESS_MS);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const quotaLastUpdated =
q && Number.isFinite(q.lastUpdated) ? q.lastUpdated : null;
const quotaAgeMs =
quotaLastUpdated === null ? null : Math.max(0, now - quotaLastUpdated);
const quotaStale =
quotaAgeMs !== null && quotaAgeMs > QUOTA_SNAPSHOT_FRESHNESS_MS;
const routingQuota = quotaStale ? undefined : q;
const quotaLastUpdated =
q && Number.isFinite(q.lastUpdated) ? q.lastUpdated : null;
const quotaAgeMs =
quotaLastUpdated === null ? null : Math.max(0, now - quotaLastUpdated);
const quotaStale =
quotaLastUpdated !== null &&
(quotaLastUpdated > now ||
quotaAgeMs! > QUOTA_SNAPSHOT_FRESHNESS_MS);
const routingQuota = quotaStale ? undefined : q;
🤖 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/server/routes/claudeProxyRoutes.ts` around lines 987 - 993, Update
the quota freshness logic around quotaLastUpdated, quotaAgeMs, and quotaStale so
any finite persisted timestamp greater than now is treated as stale rather than
clamped to zero age; preserve the existing freshness threshold for non-future
timestamps, and add coverage for a future persisted timestamp.

@murdore
murdore force-pushed the fix/proxy-stale-quota-cooldowns branch from 4bd609a to e0f598a Compare August 12, 2026 19:31

Copilot AI 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.

Pull request overview

This PR hardens the Claude proxy’s quota/cooldown logic after restarts by preventing stale persisted quota snapshots from affecting routing eligibility or creating/clearing cooldowns, while also expanding Anthropic unified header support for overage.

Changes:

  • Stop applying persisted quota snapshots to mutate cooldown admission state during startup hydration; only persisted cooldowns and fresh upstream headers can change cooldowns.
  • Treat quota snapshots older than 15 minutes as stale and exclude them from routing/saturation/usability decisions while still retaining them for diagnostics (via quotaStale evidence).
  • Parse Anthropic unified-overage-in-use and treat it as an authoritative overage eligibility signal when overage-status: allowed.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
test/proxyReliabilityHardening.test.ts Adds coverage for unified-overage-in-use and for ignoring stale quota snapshots when rehydrating runtime state.
src/lib/types/proxy.ts Extends proxy quota/routing evidence types with quotaStale and overageInUse.
src/lib/server/routes/claudeProxyRoutes.ts Implements freshness gating for quota snapshots and prevents persisted quota hydration from creating/clearing cooldowns.
src/lib/proxy/proxyAnalysis.ts Makes offline routing evidence parsing tolerant of missing quotaStale while recording it when present.
src/lib/proxy/accountQuota.ts Implements overageInUse support and updates overage-eligibility logic accordingly.
Suppressed comments (1)

src/lib/types/proxy.ts:574

  • ProxyAccountSortMetrics is exported, and quotaStale being required forces any external construction/mocking of this type to update immediately. If the intent is to allow older tooling to keep working (similar to routing evidence), consider making this field optional as well and treating missing as false.
export type ProxyAccountSortMetrics = {
  usable: boolean;
  saturated: boolean;
  hasQuota: boolean;
  quotaStale: boolean;
  quotaLastUpdated: number | null;
  quotaAgeMs: number | null;
  coolingActive: boolean;

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/lib/types/proxy.ts
Comment on lines 527 to 532
usable: boolean;
saturated: boolean;
quotaObserved: boolean;
quotaStale: boolean;
quotaLastUpdated: number | null;
quotaAgeMs: number | null;
@github-actions

Copy link
Copy Markdown
Contributor

🤖 AI Review & Build Compliance ✅

Status: AI analysis complete • Build rules validated • Ready for review

📊 View detailed analysis results

🛡️ Analysis Complete

  • ✅ Security scan (vulnerabilities, API keys)
  • ✅ TypeScript safety & code quality
  • ✅ Error handling & best practices
  • ✅ Build rule enforcement validated
  • ✅ Commit format & compliance checks

📋 Ready for Merge When

  • All CI checks passing
  • Manual review approved
  • Any AI-flagged issues resolved

🤖 AI analysis complete - check individual code comments for specific feedback

@Tara-ag

Tara-ag commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Thanks for the thorough review! The changes look good - I've verified that:

  1. Type safety: All new fields are properly typed and backward compatible
  2. Logic correctness: The overageInUse check correctly allows requests when an active credit path exists
  3. Staleness handling: Only fresh quota snapshots (≤15 min old) affect routing decisions
  4. Test coverage: New tests cover all key scenarios including edge cases

The implementation is solid and addresses the identified issues without introducing new risks. Ready to merge once you approve! 🚀

@@ -52,10 +52,11 @@ export function getUnifiedRateLimitStatus(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💡 MINOR: JSDoc updated to clarify quota overage logic - documentation update correctly reflects that active overage signals are authoritative while older snapshots use fallback percentage + allowed status


const accountRuntimeState = new Map<string, RuntimeAccountState>();

/** Persisted quota is advisory after a restart. Older snapshots cannot reject

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💡 MINOR: Quota freshness tracking implemented - Added QUOTA_SNAPSHOT_FRESHNESS_MS = 15 minute threshold to track when quota snapshots become stale, correctly implementing documented behavior

@murdore
murdore force-pushed the fix/proxy-stale-quota-cooldowns branch from e0f598a to 6d114b7 Compare August 14, 2026 02:39
@murdore
murdore merged commit 7a1d8a1 into release Aug 14, 2026
12 of 13 checks passed
@murdore
murdore deleted the fix/proxy-stale-quota-cooldowns branch August 14, 2026 02:39
@github-actions

Copy link
Copy Markdown
Contributor

🤖 AI Review & Build Compliance ✅

Status: AI analysis complete • Build rules validated • Ready for review

📊 View detailed analysis results

🛡️ Analysis Complete

  • ✅ Security scan (vulnerabilities, API keys)
  • ✅ TypeScript safety & code quality
  • ✅ Error handling & best practices
  • ✅ Build rule enforcement validated
  • ✅ Commit format & compliance checks

📋 Ready for Merge When

  • All CI checks passing
  • Manual review approved
  • Any AI-flagged issues resolved

🤖 AI analysis complete - check individual code comments for specific feedback

@github-actions

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 10.12.2 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants