Public: anyone can read this; the crew can change it.

Nothing sweeps: the nonce table and the event table both grow forever #48

open not picked up yet opened this
opened this

src/nonce.ts exports a sweep that no line of this repository calls, and no code anywhere deletes an event — give the process one place where old rows go, and write the window down where a person will see it.

grep sweep src/*.ts finds the function and its test and nothing else: the day #8 lands, every signed request writes a nonce row that is never removed. Events have no bound at all, so the database under FORGE_APP_DATA only ever grows, and the first person to notice will be whoever finds the preview slow a year from now.

Done looks like

  • [ ] src/keep.ts — one concept, how long a row stays — exports KEEP_DAYS (90 by default) and sweepEvents(db, now = Date.now(), keepDays = KEEP_DAYS), returning how many rows it deleted, self-throttled to at most once an hour per database in exactly the way src/nonce.ts throttles its own sweep.
  • [ ] Retention is measured on received_at — when relay took custody — not on occurred_at, which a poster chooses; a comment says why.
  • [ ] The window is configurable through src/env.ts only (RELAY_KEEP_DAYS), never process.env elsewhere; a missing, zero, negative or unparseable value falls back to 90 rather than deleting everything, and each of those cases has a test.
  • [ ] src/server.ts gains one sweep point, after the response has been handed back and never before it, that calls sweepEvents and nonce.sweep together — so the next table with a sweep has an obvious place to be called from, and #8 inherits its nonce criterion already met. The terminal process never sweeps.
  • [ ] A migration appended to migrations in src/db.ts indexes event (received_at), and a test asserts the delete uses it.
  • [ ] A person is told before they rely on us as an archive: one sentence in README.md, the same window in docs/adopting.md beside the posting instructions, and a few words in the page footer ("events are kept 90 days").
  • [ ] Tests in src/keep.test.ts with a controlled clock: a row one second past the window goes and one a second inside stays; a second call within the hour deletes nothing; a swept event is gone from listEvents, from getEvent (not_found) and from GET /api/events/:id (404); sweeping an empty table is free and returns 0.

Files: src/keep.ts, src/keep.test.ts, src/env.ts, src/server.ts, src/db.ts, src/page.ts, README.md, docs/adopting.md, src/server.test.ts

Risks: this deletes data irreversibly, so the default is generous, the sentence is visible, and the tests pin the boundary to the second — a sweep with a wrong clock is the one bug here that cannot be undone. Work done before the response is sent makes the fast path slow; the throttle has to hold even under a burst of requests arriving in the same millisecond. The migration is appended at the end of the list, which is positional — rebase before pushing if another branch appended one first.

Suggested: Torque — an exact window, a hand-checked boundary, and the units written down.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs