List every plan holding an inbox item on the account's inbox read
Merged
DA
7d ago+327+327+012345678901234567890123456789-28-28-01234567890123456789
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).accountInboxAnswerSchemagainsplans: 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 underLUKE_UPDATE_FIXTURES=1. The diff addsaccountInboxPlanSchemaand theplansproperty (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). NewaccountInboxPlans(userId): one grouped read,count(*)andmax(updated_at)perplan_id, filtered on the account'suser_id, joined toplanby its key witharchived_at IS NULL. It uses the same index path as the waiting items (inbox_item_user_status_updatedleads onuser_id). There's no migration. - Read (
coder-host/inbox-page.ts).accountInboxPastreads 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 writesinbox: { waiting, plans }to app state (AppInboxSlice.plans, newAppInboxPlanHolding). 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.onWaitingChangedbecomesonInboxChanged.
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 initems.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.shpasses. I didn't runEXPLAIN ANALYZEat scale for the grouped read. It's filtered on the same leadinguser_idas #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.shwas not run (Linux cloud workspace). This PR changes no UI. LUKE-159 is the manual Mac pass.
š¤ Generated with Claude Code