Skip to content

test(linq): assert retry plus wait cannot exceed deadline and default budget is bounded - #343

Merged
Miracle656 merged 1 commit into
Miracle656:mainfrom
kosisochukwu1234:test/retry-budget-and-idempotency
Oct 26, 2026
Merged

Miracle656 merged 1 commit into
Miracle656:mainfrom
kosisochukwu1234:test/retry-budget-and-idempotency

Conversation

@kosisochukwu1234

Copy link
Copy Markdown
Contributor

Summary

Addresses the issue where retry budgets and provider idempotency assumptions must be strictly pinned and proven by tests.

What is added & verified:

  1. Retry wait and deadline bounds:
    • Adds tests to src/linq/__tests__/budget.test.ts verifying that retryOnProviderFailure will not sleep or retry when now + delayMs >= deadline.
    • Asserts that when a call is made without an explicit deadline, it defaults to a bounded budget (TOTAL_BUDGET_MS = 35_000) rather than being unbounded.
  2. Idempotency pinned across all three cases:
    • Keyed offramp (idempotencyKey replay).
    • Keyed customer (customerRef uniqueness).
    • Unkeyed onramp and bill creation (pinned as non-idempotent orphan risk).
  3. Safety:
    • All tests run against FakeLinq without touching live provider routes or real credentials.

Closes #285

@Miracle656
Miracle656 merged commit 2f59e71 into Miracle656:main Oct 26, 2026
4 checks passed
@Miracle656

Copy link
Copy Markdown
Owner

Merged into main (53a6c43).

The first test is the valuable one, and it is well constructed. It pins the boundary from both sides:

  • a wait that would land exactly on the deadline must not retry
  • a wait finishing strictly before it must

Testing only the first half would pass against a predicate that never retries at all. Having both means the test describes the actual rule rather than one consequence of it. I checked it bites by loosening the comparison in retryOnProviderFailure to > deadline + 10_000 — both cases fail. That is a guard.

It also matters more than it looks. The deadline is a shared budget: a retry late in a call's life gets what is left of it, not a fresh 1,500 ms. Without this check a retry can be issued that is guaranteed to outlive the budget it is spending, which turns a bounded call into an unbounded one at exactly the moment the provider is already struggling.

One change on merge. I renamed the second case:

- proves that calls made without an explicit deadline default to a bounded budget
+ pins the default budget, which bounds a call made without a deadline

What it asserts is TOTAL_BUDGET_MS === 35_000. That is worth keeping — it catches someone editing the number without thinking about it — but it does not prove the claim in the original name. The wiring it describes lives in linqCall:

const deadline = options.deadline ?? Date.now() + TOTAL_BUDGET_MS;

and removing that ?? would leave this test green. A test whose name over-promises is worse than one that under-promises, because the next person reads the name and assumes the behaviour is covered.

If you want to close that gap properly, src/__tests__/linq/bills.test.ts already has the global.fetch = jest.fn() pattern you would need: a linqCall with no deadline, fetch always 500, and an assertion that it stops rather than retrying indefinitely. That is the test the original name described.

tsc clean, 1,330 tests pass.

https://claude.ai/code/session_01USgemLt4Rnz4SGB1Srf3GB

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.

A retry that silently doubles a budget is only caught by reading the code

2 participants