Skip to content

fix(tasks): order board and list reads newest-first, and report the window - #25

Merged
bkearns merged 2 commits into
mainfrom
fix/board-ordering-and-paging
Aug 17, 2026
Merged

fix(tasks): order board and list reads newest-first, and report the window#25
bkearns merged 2 commits into
mainfrom
fix/board-ordering-and-paging

Conversation

@bkearns

@bkearns bkearns commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

task_board and task_list silently omitted recently created tasks.

Four tasks created hours earlier were absent from both, while task_get returned them in full — so an agent that captures a deferral and reads the board back cannot see its own write, which looks like the write failed. /whats-next and /roadmap both depend on the board being the durable record.

Cause

The limit was applied by CQL with no ordering. The table is PRIMARY KEY (tenant_id, task_id), so rows arrive in task_id order and a LIMIT took an arbitrary slice rather than the newest rows. With a few hundred open tasks the window stopped including anything recent.

CQL cannot fix this with ORDER BYcreated_at is not a clustering column. So ordering has to happen after the fetch, which means fetching enough to order meaningfully and applying the caller's limit afterwards.

Changes

  • Reads fetch to MAX_FETCH_ROWS, sort newest-first, then apply limit/offset.
  • Ties break on task_id, so the order is total and a page boundary cannot return one task twice and another never.
  • list_tasks_paged reports total and truncated. A capped read that reports itself is usable; one that does not is worse than an error.
  • offset added to task_list for paging a long board.

Also: the board exceeded the token limit

Separately from the invisibility, task_board returned 619,574 characters for 382 tasks and exceeded the tool-result token limit outright, so it could not be read at all without spilling to a file first.

Rows are now slim by default — body, result and metadata dropped, summary kept because a one-line summary is what makes a listing decidable. full: true restores everything, and task_get was always the way to get detail for the task you actually pick.

CLI

frg task list keeps emitting a plain array on stdout, because frg task list | jq depends on it. It gains the ordering fix, and truncation is warned on stderr so a capped read still says so without breaking the pipe.

Verification

84 test blocks pass, clippy clean. New tests cover newest-first ordering, tie-breaking on id, and that slim drops the bulk while keeping the decidable fields.

Verified against a live board — same query, before and after:

before:  08-14 08:19  t_000d6754   (first row)
after:   08-17 14:40  t_d91e9d83   (first row)

Not merging this myself: standing rule is no auto-merge on public repos.

…indow

task_board and task_list silently omitted recently created tasks. Four tasks
created hours earlier were absent from both while task_get returned them in full,
so an agent that captured a deferral and read the board back could not see its own
write -- which looks like the write failed.

The cause is that the limit was applied by CQL with no ordering. The table is
PRIMARY KEY (tenant_id, task_id), so rows arrive in task_id order and a LIMIT
therefore took an ARBITRARY SLICE rather than the newest rows. With a few hundred
open tasks the window stopped including anything recent. CQL cannot fix this with
ORDER BY: created_at is not a clustering column, so ordering has to happen after
the fetch, which means fetching enough to order meaningfully and applying the
caller's limit afterwards.

- reads fetch to MAX_FETCH_ROWS, sort newest-first, THEN apply limit/offset;
- ties break on task_id, so the order is total and a page boundary cannot return
  one task twice and another never;
- list_tasks_paged reports total and truncated, so a capped read says so. A capped
  read that reports itself is usable; one that does not is worse than an error.

Also fixes a payload size problem that made the board unreadable by a different
route: task_board returned 619,574 characters for 382 tasks and exceeded the
tool-result token limit outright, so it could not be read without spilling to a
file. Rows are now slim by default -- body, result and metadata dropped, summary
kept because a one-line summary is what makes a listing decidable. `full: true`
restores everything, and task_get was always the way to get detail for the one
task you pick.

The CLI keeps emitting a plain array on stdout, because `frg task list | jq`
depends on it. It gains the ordering fix, and truncation is warned on STDERR so a
capped read still says so without breaking the pipe.

Verified against a live board: the newest triage rows are now 08-17 14:40, where
before the same query returned 08-14 08:19 as its first row.
The Format & Lint gate rejected the previous commit: hand-written code did not
match rustfmt. No behaviour change.
@bkearns
bkearns added this pull request to the merge queue Aug 17, 2026
Merged via the queue into main with commit 60499b9 Aug 17, 2026
5 checks passed
@bkearns bkearns mentioned this pull request Aug 17, 2026
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.

1 participant