Cap stored idempotency rows per user

Task 12553 · Done · Coder · created · updated

Deferred by the server-idempotency child (PR #7686). `request_idempotency` stores each console write's answer (up to `MAX_BYTES` = 1 MiB, `apps/api/app/idempotency.py:90`) for 24 h, pruned by cron (`prune`, :259). Only waiting copies are capped (`MAX_WAITERS`, :97). Direct (non-relayed) writes have no per-user write budget, so one signed-in user can grow the table without bound for 24 h with large write answers. This is a storage-abuse and data-integrity hardening gap on a security-surface table. Fix (no new surface): when a claim is inserted (`_claim`, :219), count the user's live rows (younger than 24 h). Past a constant cap (e.g. `MAX_ROWS_PER_ADMIN = 2000`, beside its peers), still run the request but store its answer as status only, the same path as an over-`MAX_BYTES` answer. Never refuse the write itself. Emit one log line naming the admin id when the cap is hit. Acceptance: - AC-1: a pytest fills a user to the cap, then sends another keyed write. The write applies once, a replay answers `409 idempotency_replay_unavailable`, and a second user is unaffected. - AC-2: all the existing idempotency tests pass unchanged. Out of scope: the relay budgets, the web client, the retention window, and machine callers. Done means: - AC-1 and AC-2 green. - `./dc check quick` green, the PR merged via the merge lane, and the Jaah Deploy to dev green.

Outcome

Added a per-user cap (MAX_ROWS_PER_ADMIN = 2000). Beyond it a write still runs once and its answer is stored as status only, so a replay returns 409. AC-1 and AC-2 pass (58/58), quick gate green, merged ab2d03bb. The deploy for that commit was superseded by the next develop deploy. Memory: none applied.

Pull request

Artifacts

Activity

  • Ready
  • Runner started
  • Runner ended (done)