Skip to content

fix(support): no refund on a timed-out confirmation, UTC-day-safe budget refund, stale-IP eviction (T-6911) - #668

Merged
AminDhouib merged 1 commit into
devfrom
fix/support-confirm-leftovers-6911
Oct 26, 2026
Merged

AminDhouib merged 1 commit into
devfrom
fix/support-confirm-leftovers-6911

Conversation

@AminDhouib

@AminDhouib AminDhouib commented Oct 26, 2026 •

Copy link
Copy Markdown
Member

Fixes the LOW leftovers from the #645 re-review (T-6911). Items 3 and 4 are deliberate policy and stay unchanged: the 200/day global cap can be used up by about 5 IPs, and requests with no IP share one unknown bucket, which fails closed.

Changes

  • A timed-out confirmation no longer refunds. If our 5 s abort fires after the request was sent, Sendly may already have accepted the mail.
    • postToSendly now resolves unknown, checked via controller.signal.aborted.
    • The route keeps the address slot and the IP/daily budget for it.
    • The response reports confirmation: "unknown", a new neutral ConfirmationLegStatus.
    • So a retry cannot mail the submitter twice. Definite failures (non-2xx, network error) still refund. The team-notification leg still maps a timeout to failed.
  • Budget refunds are safe across a UTC day. releaseConfirmationBudget decrements the daily cap only when the IP's newest confirmation was taken on the current UTC day. The hourly IP allowance is still returned, and an IP with no record refunds nothing.
  • Stale byIp entries are evicted. Entries whose hour has passed are swept at most once a minute, and before the hard cap would evict a live IP. The 10k hard cap stays.

Behavior notes

  • The existing "aborts the confirmation send after 5 seconds" test now expects unknown instead of failed. That is the intended change.
  • The support form does not read confirmation, so nothing user-facing changes.
  • No changeset: @useupup/landing is in the ignore list of .changeset/config.json.

Test plan (run on devino-forth)

  • RED (tests only): Test Files 2 failed (2) | Tests 6 failed | 67 passed (73)
  • GREEN:
    • Test Files 2 passed (2) | Tests 73 passed (73)
    • full landing suite: 58 files / 813 tests passed
    • landing typecheck clean
    • pre-commit and pre-push hooks green

Known tradeoff (from review)

fetch cannot tell an abort while connecting from an abort after the body was sent. So if Sendly hangs at connect, the confirmation is also reported as unknown, and the slot and budget are kept, not refunded. This direction over-counts during a Sendly outage and can never mail a submitter twice. An outage then shows up as throttled on retry instead of as duplicate mail.

… refunds to their UTC day, sweep stale IPs

Leftovers from the re-review of #645 (T-6911).

- A confirmation whose 5 s abort fires after the request was sent used to
  be reported as failed and refunded the address slot and the IP/daily
  budget, so a retry could mail the submitter twice. postToSendly now
  resolves "unknown" when our own abort fired; the route keeps every
  allowance for it and the response reports confirmation: "unknown"
  (a new neutral ConfirmationLegStatus). The team-notification leg still
  maps a timeout to "failed" (no refund to protect there).
- releaseConfirmationBudget decremented today.count even after the UTC
  day rolled over. It now refunds the daily cap only when the IP newest
  confirmation was taken on the current UTC day, and does nothing for an
  IP with no record. The hourly IP allowance is still returned.
- byIp kept expired entries until the 10k cap. Entries whose hour has
  passed are now swept at most once a minute (and before the hard cap
  evicts a live IP); the hard cap stays.

RED (tests only, before the fix):
  FAIL confirmation-throttle.test.ts > budget release across the UTC day boundary > does not refund the new day when the slot was taken the day before
  FAIL confirmation-throttle.test.ts > budget release across the UTC day boundary > does not count down an IP it has no record of
  FAIL confirmation-throttle.test.ts > stale per-IP entries > drops IPs whose hour has passed once traffic arrives, keeping the map small
  FAIL confirmation-throttle.test.ts > stale per-IP entries > keeps an IP that is still inside its hour when expired ones are swept
  FAIL support-route.test.ts > ... > aborts the confirmation send after 5 seconds instead of holding the response
  FAIL support-route.test.ts > ... > keeps the address allowance and IP budget, and reports unknown, when the 5 s abort fires after the request went out
  Test Files  2 failed (2) | Tests  6 failed | 67 passed (73)

GREEN (after the fix): Test Files 2 passed (2) | Tests 73 passed (73);
full landing suite 58 files / 813 tests passed; landing typecheck clean.
The existing 5 s abort test now expects "unknown" instead of "failed".
@codesandbox

codesandbox Bot commented Oct 26, 2026

Copy link
Copy Markdown

Review or Edit in CodeSandbox

Open the branch in Web Editor • VS Code • Insiders

Open Preview

@AminDhouib
AminDhouib merged commit 721b7c6 into dev Oct 26, 2026
18 checks passed
@AminDhouib
AminDhouib deleted the fix/support-confirm-leftovers-6911 branch October 26, 2026 04:11
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.

1 participant