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

Older proposals are reachable: the list says what it is showing and pages past it #50

open not picked up yet opened this
opened this

listProposals ends in LIMIT ?1 with a default of 100 and a cap, and / never mentions it. A group that has decided a hundred and one things has a record whose oldest entry cannot be reached from any page in this app, and nothing on the screen admits it. A record with a silent horizon is not a record.

What done looks like

  • [ ] listProposals takes an optional before (a proposal id) and returns, with the rows, whether there are more behind them — from the one query it already runs (ask for limit + 1 rows and drop the extra, never a second COUNT(*) over the table).
  • [ ] before is validated at the boundary: a whole number, not a numeric string coerced (#41 is the precedent), and anything else is invalid with a sentence.
  • [ ] / shows an "Older proposals" link when there are more, carrying ?before=<id> alongside whatever ?state= is set (#37) — plain links, no JavaScript, and the link is a <a> a guest can bookmark and share.
  • [ ] A page of older proposals says where it is ("Proposals older than #41") and links back to the newest, so nobody is stranded on page four with only a back button.
  • [ ] GET /api/proposals takes before and returns it in its shape, so a script can walk the whole record; the README shows the loop in three lines.
  • [ ] MCP's list_proposals takes before with one sentence saying how to page, because an agent summarising a group's history is the caller that will hit the cap first.
  • [ ] The terminal's list pages with the same action rather than raising its own limit.
  • [ ] Tests: 150 seeded proposals are all reachable by following before to the end, with no row seen twice and none skipped; before on a nonexistent id answers an empty page rather than an error; before as "12" is refused; ?state=decided&before=… keeps both; the last page offers no "Older" link.
  • [ ] bun test is green and a page of 100 rows still answers in single-digit milliseconds.

Files I expect to change: src/actions.ts, src/actions.test.ts, src/pages/home.ts, src/routes.ts, src/mcp.ts, src/tty.ts, src/server.test.ts, README.md.

Risks: keyset paging on id DESC is correct and an OFFSET is not — with proposals being opened while somebody reads, an offset shows the same row twice and hides another. If #37's sort=active has landed, paging by activity needs its own keyset and this issue does not owe one: page the default order, and say in the pull that the active sort shows its first page only. Do not raise the limit as a substitute for paging; the cap is what makes the page fast.

Fit: Ledger — the record reachable to its last row. A person assigns; I do not.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs