Skip to content

fix(db): ignore non-finite rate_limited_until writes, preserve null clear - #12788

Merged
diegosouzapw merged 1 commit into
diegosouzapw:release/v3.8.51from
maxmad64bis:fix/ratelimit-write-guard
Sep 8, 2026
Merged

diegosouzapw merged 1 commit into
diegosouzapw:release/v3.8.51from
maxmad64bis:fix/ratelimit-write-guard

Conversation

@maxmad64bis

@maxmad64bis maxmad64bis commented Sep 5, 2026 •

Copy link
Copy Markdown
Contributor

⚠️ base-red inherited: #12732

Summary

Rate-limit cooldowns are timestamps in the database, and until now any value got written — including ones that make no sense, like NaN, or ones already in the past. A stale write could leave a connection looking locked (or unlocked) at the wrong time. Now only future timestamps are stored; anything expired or invalid is quietly skipped, and clearing a cooldown works exactly as before.

Related Issues

Validation

  • Change type: DB
  • Focused tests and category gates from the golden path
  • npm run lint
  • Reconciled with the current active release base; focused checks rerun afterward
  • Production-code changes include a new or updated automated test in this PR

Tests Added Or Updated

  • tests/unit/db-rate-limit-guard.test.ts (new) — 6 cases: NaN ignored, ±Infinity ignored, past/0 ignored, future writes through, null clear preserved, expired write doesn't overwrite a live row (6/6 pass; 3 fail before the guard as designed)
  • Neighbors green: every suite under tests/unit that calls setConnectionRateLimitUntil — db-providers-crud, db-providers-split, antigravity-429-quota-cooldown, persist-429-cooldown-account-fallback, cooldown-epoch-string-3954, mark-account-unavailable-numeric-epoch-guard (82/82 pass)

Coverage Notes

  • Changes src/lib/db/providers/rateLimit.ts (one fused guard + comment at the head of setConnectionRateLimitUntil; readers, markConnectionRateLimitedUntil, and clearConnectionRateLimit untouched). Covered by the new test file; no new branches beyond the guard itself.

Reviewer Notes

  • One deliberate call: past timestamps are noops rather than implicit clears, so an expired write can never overwrite a live future row — the only clear path stays null via clearConnectionRateLimit. If any caller relied on writing the past to "unlock" a row, that pattern now needs an explicit clear (no such caller found in the test suites above).
  • No migrations, no flags, no routing changes. Single commit.

@maxmad64bis
maxmad64bis force-pushed the fix/ratelimit-write-guard branch 2 times, most recently from d86ca05 to 324d36f Compare September 5, 2026 10:19
@maxmad64bis
maxmad64bis force-pushed the fix/ratelimit-write-guard branch from 324d36f to 7ad7013 Compare September 6, 2026 01:23
@diegosouzapw
diegosouzapw merged commit 678af2e into diegosouzapw:release/v3.8.51 Sep 8, 2026
8 of 16 checks passed
diegosouzapw pushed a commit that referenced this pull request Sep 10, 2026
…ot headroom (#12951)

Validado numa worktree combinada com a onda de persistência desta leva sobre `release/v3.8.51`: check-file-size e check-changelog-integrity OK, typecheck:core limpo, check-api-typecheck OK (289). Revalidei o head atual mergeado com o tip: typecheck:core limpo e **36/36** entre `db-rate-limit-guard` e as suítes desta PR.

Levantar o cooldown do escopo pai sem deixar os filhos aninhados presos é o miolo — um cooldown órfão em filho é invisível no dashboard e mantém a conexão fora de rota sem explicação.

**Nota de coordenação:** o `setConnectionRateLimitUntil` colidiu com o #12788 (guard contra timestamp não-finito ou já expirado), que mergeei nesta mesma onda. Eu tinha resolvido a integração na minha worktree, mas ao empurrar o push foi rejeitado — você já tinha empurrado `441fd44`, `f853ba5` e `af2ed01` com a integração feita, e a sua ordenação é equivalente à minha. Descartei a minha e mantive a sua; o crédito é seu inteiro. Fica o registro de que push rejeitado não é erro leve: se eu tivesse mergeado sem reler, teria levado a branch errada.
@maxmad64bis
maxmad64bis deleted the fix/ratelimit-write-guard branch September 24, 2026 21:15
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…lear (diegosouzapw#12788)

Validado numa worktree combinada com a onda de persistência desta leva sobre `release/v3.8.51`: check-file-size e check-changelog-integrity OK, typecheck:core limpo, check-api-typecheck OK (289, dentro da baseline), 70 testes focados no runner Node e 1 no vitest, todos verdes.

Persistir `NaN`/`Infinity` numa coluna TEXT envenena toda leitura futura, e um timestamp já expirado sobrescrevendo uma linha viva é pior que não escrever nada. O guard fundido na cabeça da função cobre os dois sem tocar leitores nem o caminho de clear.

Os 6 casos do teste incluem o que mais importa: `null` continua limpando, e uma escrita expirada não derruba um cooldown ativo. Nota: 3 deles falham antes do guard, como você registrou.

**Integração:** este arquivo colidiu com o diegosouzapw#12951, que também guarda a cabeça de `setConnectionRateLimitUntil` — lá o `null` vira caminho de clear que também remove os cooldowns filhos do Codex. Os dois compõem: trata-se o `null` primeiro (clear + return), e o seu guard de finitude/expiração passa a valer para os não-nulos. Ambos preservados.
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…ot headroom (diegosouzapw#12951)

Validado numa worktree combinada com a onda de persistência desta leva sobre `release/v3.8.51`: check-file-size e check-changelog-integrity OK, typecheck:core limpo, check-api-typecheck OK (289). Revalidei o head atual mergeado com o tip: typecheck:core limpo e **36/36** entre `db-rate-limit-guard` e as suítes desta PR.

Levantar o cooldown do escopo pai sem deixar os filhos aninhados presos é o miolo — um cooldown órfão em filho é invisível no dashboard e mantém a conexão fora de rota sem explicação.

**Nota de coordenação:** o `setConnectionRateLimitUntil` colidiu com o diegosouzapw#12788 (guard contra timestamp não-finito ou já expirado), que mergeei nesta mesma onda. Eu tinha resolvido a integração na minha worktree, mas ao empurrar o push foi rejeitado — você já tinha empurrado `441fd44`, `f853ba5` e `af2ed01` com a integração feita, e a sua ordenação é equivalente à minha. Descartei a minha e mantive a sua; o crédito é seu inteiro. Fica o registro de que push rejeitado não é erro leve: se eu tivesse mergeado sem reler, teria levado a branch errada.
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