List every plan holding an inbox item on the account's inbox read

Merged
DA
7d ago
+327-28

PR 3 of the Inbox rollout: the data the global Inbox view (PR 4) lists. Dean asked for "another sidebar with all the plans that have addressed or unaddressed inbox items". The account's inbox read (#2216) carries open items only, so a plan whose items were all answered appeared nowhere. This adds that list.

What changes

  • Wire (@sidecar/hosted/account-inbox-wire). accountInboxAnswerSchema gains plans: AccountInboxPlan[], each { planId, items, updatedAt }: every plan the account hasn't archived that holds any item, waiting or settled, with how many it holds and when the latest changed, newest first. Goldens are re-recorded under LUKE_UPDATE_FIXTURES=1. The diff adds accountInboxPlanSchema and the plans property (now required) to the answer and to the view schema that wraps it, and changes nothing else. An older desktop ignores the new key, as answers do here.
  • Store (inbox-store.ts). New accountInboxPlans(userId): one grouped read, count(*) and max(updated_at) per plan_id, filtered on the account's user_id, joined to plan by its key with archived_at IS NULL. It uses the same index path as the waiting items (inbox_item_user_status_updated leads on user_id). There's no migration.
  • Read (coder-host/inbox-page.ts). accountInboxPast reads the plans once per answer, never on the 2s stamp looks inside the hold. The cursor is unchanged and still digests only the open items. The plan list moves with them: an item always opens before it settles, so posting, answering and closing each move the cursor. What moves the list alone (archiving a plan whose items are all settled) is answered at the hold's end at the latest.
  • Main (agent-notices.ts). It writes inbox: { waiting, plans } to app state (AppInboxSlice.plans, new AppInboxPlanHolding). An answer at a cursor that stands but with different plans writes the plans alone and announces nothing. Signing out or switching accounts clears them with the rest. onWaitingChanged becomes onInboxChanged.

The renderer reads nothing new yet. PR 4 draws the list.

Tests

  • apps/web/tests/coding-agents-app.test.ts (route, PGlite): the account's inbox lists every plan holding an item, waiting or settled, latest changed first, with its count. An archived plan's and another account's are left out, and only waiting items are in items.
  • agent-notices.test.ts: plans are written beside what waits. An answer at the same cursor whose plans moved writes them alone and announces nothing, the same plans again write nothing, and another account lets them go.
  • The client, host-operator and gateway composer round trips now carry plans.

Validation

  • ./scripts/check.sh passes. I didn't run EXPLAIN ANALYZE at scale for the grouped read. It's filtered on the same leading user_id as #2216's measured read, but it reads settled rows too, so it costs more per answer. It runs once per answer (on a change, or at the hold's end), not once per look.
  • CI cannot verify the Mac UI, and ./scripts/verify.sh was not run (Linux cloud workspace). This PR changes no UI. LUKE-159 is the manual Mac pass.

šŸ¤– Generated with Claude Code


Devin Review


Open workspace in Conductor