Notifications say 100+ unread when the server's cap is reached

Merged
JE
2mo ago
+141-7

What

notifications list no longer reports a capped unread list as a count.

  • When the unreads list holds 100 items (the server cap), the summary says 100+ unread, and the page total gets the same +: 150+ notification(s) (100+ unread). A notice says the server returns no more than 100 and --page does not reach the rest.
  • JSON adds one boolean at the top level of data: unreads_capped (always present, true at the cap). Every existing field keeps its name, place and shape; the result is the SDK struct embedded in a wrapper with that one extra field.
  • --page help, the list long help, the agent notes, and the "next" breadcrumb now say --page pages read notifications only and every page repeats the same unreads.
  • skills/basecamp/SKILL.md documents the cap and the flag.

Why

The server returns at most 100 unreads (MAX_UNREADS = 100 in bc3's My::ReadingsController, and documented in the API) and pages only read items. The CLI printed len(unreads) as the unread total and its "Next page" breadcrumb implied the whole feed pages, so an account with 235 unreads showed "100 unread" on every page.

This is step 1 only. Reaching every unread needs a bc3 API change (an uncapped unreads endpoint), tracked separately; nothing here tries to page past the cap.

Testing

  • New tests: 100 unreads give 100+, unreads_capped: true, a notice, and unchanged unreads/reads arrays; 99 unreads give the exact count, unreads_capped: false and no notice; the --page usage and the next-page breadcrumb say read notifications only.
  • Styled, Markdown and quiet output checked by hand at the cap.
  • make -k check compared against a clean origin/main worktree on the same Mac: the same targets fail on both (lint: five pre-existing darwin gosec/unconvert/unused findings; test: pre-existing TTY/interactive and connector timing failures). The only difference is TestNoErrorPathCarriesTheSecretOut and TestAnAgentThatStopsReadingCannotHoldCancelOrClose in internal/connector/driver/claude, which this change does not touch and which fail on origin/main too when rerun. Every other target (e2e, surface, skill drift, naming, provenance, tidy) passes.

Summary by cubic

notifications list no longer presents the server's 100-item unread cap as an exact total. When the cap is reached, the summary reads "100+ unread", JSON adds unreads_capped: true marking 100 as a lower bound, and a notice explains that --page does not reach the rest.

  • Existing data fields keep their shape; the SDK result is embedded in a wrapper with one extra boolean.
  • Help text, the agent note, the "next" breadcrumb, and skills/basecamp/SKILL.md now state that --page pages read notifications only and every page repeats the same unreads.