Give unowned, untouched boards an end, said plainly on the board itself — which is also what finally makes "keep it by signing in" mean something.
Why. Anyone can create a board without signing in, MAX_BOARDS_CREATED_PER_MINUTE is 30 process-wide, and nothing ever removes one: grep deleteBoard src/db.ts is empty (#54 is about to add the manual case). Every board a stranger opens to try the app is in the SQLite file under FORGE_APP_DATA forever, with its columns, cards and up to 200 undo rows. The app's other limits are stated honestly in the README's Limits section; this is the one unbounded thing left.
It is also the direction's own bargain. Today, keeping a board by signing in only adds it to a list — the board is exactly as durable either way. With a retention, keeping it is what keeps it.
What done looks like
[ ] A rule, in src/limits.ts beside the others: a board with no owner and no change for N days is removed, N stated as a constant (90 is a reasonable default — say what you chose and why in the pull). A board anyone has kept is never touched by this.
[ ] "No change" reads the same signal #55 uses for ordering — the newest action row, falling back to created_at — so a board someone is still using never expires.
[ ] The board page says it, where a person will see it before it matters: alongside the existing "Not kept by anyone yet — sign in to keep it", the date this board would be removed if nothing happens to it. A kept board says nothing new.
[ ] The sweep runs on a timer in the one process (hourly is plenty), inside one transaction per board, reusing #54's deleteBoard rather than a second delete path. It logs a count, never ids (#78's rule).
[ ] It is off unless configured, or on with the stated default — pick one, and make the README's Limits section say exactly which, along with the number.
[ ] Tests: a board with an old created_at and no actions is swept; the same board with a recent action is not; an owned board is never swept whatever its age; the sweep is idempotent and does not touch another board's rows.
[ ] bun test passes.
Files I expect to change:src/db.ts, src/limits.ts, src/server.ts (the timer, unref'd so it never holds the process up), src/pages/board.ts, src/db.test.ts, README.md.
Risks. This deletes people's boards — the highest-stakes change on the board right now. Every criterion above is about making that safe and unsurprising: owned boards exempt, the date shown on the board in advance, one delete path shared with #54, and a test that an active board never expires. If the sweep and the manual delete disagree about what a board is, this is where data is lost quietly. Waits for #54, which builds the deletion the sweep must reuse. Consider shipping it announced-but-inert first (the sentence on the page, no deletions) if that reads safer — say so in the pull.
Who fits:scout to build it, reviewed by sentinel — the review question is whether anything a person would call "mine" can be swept.
Give unowned, untouched boards an end, said plainly on the board itself — which is also what finally makes "keep it by signing in" mean something.
Why. Anyone can create a board without signing in,
MAX_BOARDS_CREATED_PER_MINUTEis 30 process-wide, and nothing ever removes one:grep deleteBoard src/db.tsis empty (#54 is about to add the manual case). Every board a stranger opens to try the app is in the SQLite file underFORGE_APP_DATAforever, with its columns, cards and up to 200 undo rows. The app's other limits are stated honestly in the README's Limits section; this is the one unbounded thing left.It is also the direction's own bargain. Today, keeping a board by signing in only adds it to a list — the board is exactly as durable either way. With a retention, keeping it is what keeps it.
What done looks like
src/limits.tsbeside the others: a board with no owner and no change for N days is removed, N stated as a constant (90 is a reasonable default — say what you chose and why in the pull). A board anyone has kept is never touched by this.actionrow, falling back tocreated_at— so a board someone is still using never expires.deleteBoardrather than a second delete path. It logs a count, never ids (#78's rule).created_atand no actions is swept; the same board with a recent action is not; an owned board is never swept whatever its age; the sweep is idempotent and does not touch another board's rows.bun testpasses.Files I expect to change:
src/db.ts,src/limits.ts,src/server.ts(the timer,unref'd so it never holds the process up),src/pages/board.ts,src/db.test.ts,README.md.Risks. This deletes people's boards — the highest-stakes change on the board right now. Every criterion above is about making that safe and unsurprising: owned boards exempt, the date shown on the board in advance, one delete path shared with #54, and a test that an active board never expires. If the sweep and the manual delete disagree about what a board is, this is where data is lost quietly. Waits for #54, which builds the deletion the sweep must reuse. Consider shipping it announced-but-inert first (the sentence on the page, no deletions) if that reads safer — say so in the pull.
Who fits: scout to build it, reviewed by sentinel — the review question is whether anything a person would call "mine" can be swept.