Skip to content

test: property-check the circuit breaker's availability contract#592

Open
ndycode wants to merge 2 commits into
mainfrom
claude/audit-73-circuit-breaker-property
Open

test: property-check the circuit breaker's availability contract#592
ndycode wants to merge 2 commits into
mainfrom
claude/audit-73-circuit-breaker-property

Conversation

@ndycode

@ndycode ndycode commented Jun 11, 2026

Copy link
Copy Markdown
Owner

Summary

  • Adds a fast-check property suite for lib/circuit-breaker.ts — the per-account failure-isolation state machine that rotation uses to decide routability. The existing example suite (28 tests) covers specific paths; this companion pins the contracts that have to hold under any interleaving of failures, successes, attempts, and clock advances.

What Changed

New test/property/circuit-breaker.property.test.ts (5 properties, real CircuitBreaker under vi.useFakeTimers() with small windows so generated sequences cross every timing boundary):

  1. Availability is a faithful prediction — after any event sequence, isAvailable(now) and getTimeUntilAvailable(now) agree with what the very next canExecute() actually does (allows vs throws CircuitOpenError), and wait === 0 ⇔ available. This is the load-bearing one: rotation polls the availability view to route accounts, so a stale or disagreeing answer would mis-route.
  2. Open-state timing is exact — from any prior history, a fresh forced open rejects strictly before resetTimeoutMs (with getTimeUntilAvailable returning the exact remainder) and admits the half-open probe at exactly resetTimeoutMs.
  3. Threshold exactness — failures inside one window open the circuit at exactly failureThreshold, never below it.
  4. Window expiry — consecutive failures spaced beyond failureWindowMs never accumulate; the circuit stays closed with a count of 1 regardless of how many arrive.
  5. Half-open probe discipline — exactly one probe is admitted per slot; extra attempts are rejected; the probe's success closes with a clean failure count, its failure reopens for a full fresh timeout.

One harness bug was caught by fast-check itself during development (property 2 originally assumed the breaker wasn't already open after the arbitrary prefix — counterexample found on run 14); the fix forces a fresh timestamped open, which also strengthens the property to "reset + threshold failures always yields a clean open from any history". No SUT bugs found — the breaker's timing contract held everywhere.

Validation

  • npm test -- test/property/circuit-breaker.property.test.ts test/circuit-breaker.test.ts — 33/33 (new 5 + existing 28 untouched)
  • npm run typecheck (also via pre-commit hook)
  • npx eslint test/property/circuit-breaker.property.test.ts --max-warnings=0
  • Fake timers scoped per-property with try/finally vi.useRealTimers() plus a guard afterEach, matching the repo's wall-clock test conventions

Docs and Governance Checklist

  • Test-only; no behavior or docs surface changed

Risk and Rollback

https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB


Generated by Claude Code

note: greptile review for oc-chatgpt-multi-auth. cite files like lib/foo.ts:123. confirm regression tests + windows concurrency/token redaction coverage.

Greptile Summary

adds a fast-check property suite for lib/circuit-breaker.ts, complementing the existing 28 example-based tests with 5 contracts that must hold under any interleaving of failures, successes, and clock advances. fake-timer scoping, import style, and fc.assert usage all match repo conventions.

  • property 1 pins that isAvailable(now) / getTimeUntilAvailable(now) are a faithful prediction of the very next canExecute() call — the contract rotation depends on for account routing.
  • properties 2–5 pin open-state timing exactness (including getTimeUntilReset() under fake timers), threshold triggering, failure-window expiry, and half-open probe discipline across arbitrary prior history.
  • no SUT bugs found; the one harness bug caught during development (stale open timestamp after arbitrary prefix) was fixed by the reset() + threshold-failures pattern used in property 2.

Confidence Score: 5/5

additive test-only change with no SUT modifications; safe to merge.

the change is a single new test file with no modifications to production code. all five properties are logically sound against the SUT implementation, fake-timer scoping follows the repo's try/finally + afterEach convention, and the previously flagged getTimeUntilReset() gap is now covered in property 2.

no files require special attention.

Important Files Changed

Filename Overview
test/property/circuit-breaker.property.test.ts new property suite (5 properties) covering availability agreement, timing exactness, threshold, window expiry, and half-open probe discipline; getTimeUntilReset() now asserted in property 2; fake-timer scoping via try/finally + afterEach matches repo convention; no logic defects found

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[arbSequence prefix] --> B{force open\nreset + threshold failures}
    B --> C[prop 1: isAvailable/getTimeUntilAvailable\nagrees with canExecute]
    B --> D[prop 2: open-state timing exact\nearlyMs < resetTimeout → reject\nat resetTimeout → half-open probe]
    B --> E[prop 3: threshold exactness\nopens at exactly failureThreshold]
    B --> F[prop 4: window expiry\ngaps > failureWindowMs → count stays 1]
    B --> G[prop 5: half-open probe discipline\none probe admitted; success→closed; failure→open]
    D --> H{getTimeUntilReset}
    H -->|open state| I[resetTimeoutMs - elapsed]
    H -->|non-open state| J[0]
Loading

Reviews (2): Last reviewed commit: "test: pin getTimeUntilReset alongside th..." | Re-trigger Greptile

Five fast-check properties over the real CircuitBreaker under fake
timers (small windows so sequences cross every boundary):

- isAvailable/getTimeUntilAvailable agree with the very next
  canExecute outcome after ANY event sequence - the polling view
  callers route on is a faithful prediction, never stale
- an open circuit rejects strictly before resetTimeoutMs and admits
  the probe exactly at it, from any prior history (fresh forced open)
- opens exactly at failureThreshold inside one window, never below
- failures spaced beyond failureWindowMs never accumulate
- the half-open slot admits exactly one probe; success closes with a
  clean failure count, failure reopens for a full timeout

Companion to the property suites in #574/#575/#579; same conventions.

https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@ndycode, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 1 minute and 23 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more credits in the billing tab to continue.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: a9c7c464-ab96-472f-a837-ef3db3df1c3d

📥 Commits

Reviewing files that changed from the base of the PR and between c255e14 and 5da0f2b.

📒 Files selected for processing (1)
  • test/property/circuit-breaker.property.test.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/audit-73-circuit-breaker-property
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch claude/audit-73-circuit-breaker-property

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 and usage tips.

Comment thread test/property/circuit-breaker.property.test.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants