WIP: Attention Inbox end-to-end (WI-parked trigger) #284

Closed
toasterson wants to merge 1 commit from claude/wi-019f1777-attention-inbox-end-to-end-wi-parked-tri into main
Owner

Anima work item 019f1777-b171-7390-ac92-a9583112a848.

What to build

The tracer bullet that establishes the whole Attention Inbox pipeline with ONE trigger, proving proto → server read-model → PWA component → tests. The dashboard gains an Inbox as its hero element (above Runner Fleet) that lists parked work items (status needs_human), one routable row per WI, each linking to that WI. This replaces the old "Recent Activity" flat list section (delete it). Counters and the other three triggers are separate WIs — do NOT touch them here.

End-to-end behaviour: open the dashboard → see an "Inbox" section at the top → each parked WI in a project I have a role on shows as a row (title + "parked" reason + relative age) → clicking routes to the WI detail. When a WI is un-parked, its row disappears on next load (state-derived, no dismiss).

Pushed context

Design is fixed by ADR 0015 (docs/adr/0015-dashboard-attention-inbox.md) and the Attention feed glossary entry in CONTEXT.md — read both first. Key constraints from the grill:

  • Inbox is a deduped state-worklist (one row per entity), NOT a chronological log. Ordered by urgency/age.
  • Scope is project-membership RBAC: only items from projects the caller has a role on. WorkItems have no assignee — a row means "needs someone with a role on this project". Mirror how existing dashboard queries scope (see crates/anima-server/src/services/dashboard.rs build_dashboard, and RBAC in crates/anima-core/src/rbac/).
  • "parked" = WorkItemStatus::NeedsHuman (DB status = 'needs_human'); see crates/anima-core/src/domain/workitem.rs.

Proto + server (fold into the existing Dashboard, reuse live updates — do NOT add a new RPC):

  • proto/anima/v1/dashboard.proto — add a message AttentionItem { string id; string trigger; string title; string project_id; string work_item_id; string slice_id; string plan_id; string document_id; string route; string reason; google.protobuf.Timestamp occurred_at; } and repeated AttentionItem attention_inbox = N; on message Dashboard. trigger is a string taxonomy ("wi_parked" now; "decision_pending" / "slice_done" / "deliverable_review" added by later WIs). route is the app path the row links to.
  • Regenerate stubs after the proto edit: Rust via the build, PWA via npm run generate in anima-pwa/ — committed src/gen/* must be regenerated and reconciled (see the PWA codegen-drift convention; stale gen masks drift).
  • crates/anima-server/src/services/dashboard.rs — in build_dashboard, add a query for parked WIs (RBAC-scoped) and map them to AttentionItem { trigger: "wi_parked", route: "/work-items/<id>" (match the PWA's actual WI route), reason: "parked — needs you", occurred_at: updated_at }. Add a WorkItemRepo query if needed (crates/anima-db/src/repo/workitem.rs).

PWA:

  • anima-pwa/src/pages/Dashboard/Dashboard.tsx — remove the "Recent Activity" <section> (~lines 180-208) and its listActivity usage; add an Inbox section as the first child (above Runner Fleet). Source rows from getDashboard().attentionInbox (extend the dashboard fetch in anima-pwa/src/lib/grpcApi.tsgetFleet already calls dashboardClient.getDashboard({}); add an attention_inbox mapping rather than a second round-trip).
  • New component anima-pwa/src/pages/Dashboard/AttentionInbox.tsx (+ a Row): per-trigger icon/colour (only wi_parked now, but switch on trigger so later WIs slot in), title, reason, relative age, whole row is a <Link to={route}>. Empty state: "Inbox zero — nothing needs you."
  • Working UI label: "Inbox" (final label still open — keep it a single constant so it's trivial to change).
  • Keep mock parity: anima-pwa/src/lib/mockApi.ts + mockData.ts should return a couple of attentionInbox fixtures so tests + mock mode render.

Acceptance criteria

  • AttentionItem + Dashboard.attention_inbox added to the proto; Rust + PWA stubs regenerated and committed.
  • build_dashboard returns parked WIs as attention_inbox items, scoped to the caller's RBAC projects (a user with no role on a project does NOT see its parked WIs).
  • Dashboard renders an Inbox section above Runner Fleet; each parked WI is a row that routes to the WI; un-parked WIs no longer appear.
  • The old "Recent Activity" section and its listActivity call are removed from the dashboard.
  • Empty state renders when there are no items.
  • cargo check -p anima-server -p anima-db clean; npm run verify green (a Dashboard/AttentionInbox test asserts a parked row renders + routes).

Blocked by

  • None — can start immediately.
Anima work item `019f1777-b171-7390-ac92-a9583112a848`. ## What to build The tracer bullet that establishes the whole Attention Inbox pipeline with ONE trigger, proving proto → server read-model → PWA component → tests. The dashboard gains an **Inbox** as its hero element (above Runner Fleet) that lists **parked work items** (status `needs_human`), one routable row per WI, each linking to that WI. This replaces the old "Recent Activity" flat list section (delete it). Counters and the other three triggers are separate WIs — do NOT touch them here. End-to-end behaviour: open the dashboard → see an "Inbox" section at the top → each parked WI in a project I have a role on shows as a row (title + "parked" reason + relative age) → clicking routes to the WI detail. When a WI is un-parked, its row disappears on next load (state-derived, no dismiss). ## Pushed context Design is fixed by **ADR 0015** (`docs/adr/0015-dashboard-attention-inbox.md`) and the **Attention feed** glossary entry in `CONTEXT.md` — read both first. Key constraints from the grill: - Inbox is a **deduped state-worklist** (one row per entity), NOT a chronological log. Ordered by urgency/age. - Scope is **project-membership RBAC**: only items from projects the caller has a role on. WorkItems have no assignee — a row means "needs someone with a role on this project". Mirror how existing dashboard queries scope (see `crates/anima-server/src/services/dashboard.rs` `build_dashboard`, and RBAC in `crates/anima-core/src/rbac/`). - "parked" = `WorkItemStatus::NeedsHuman` (DB `status = 'needs_human'`); see `crates/anima-core/src/domain/workitem.rs`. Proto + server (fold into the existing Dashboard, reuse live updates — do NOT add a new RPC): - `proto/anima/v1/dashboard.proto` — add a message `AttentionItem { string id; string trigger; string title; string project_id; string work_item_id; string slice_id; string plan_id; string document_id; string route; string reason; google.protobuf.Timestamp occurred_at; }` and `repeated AttentionItem attention_inbox = N;` on `message Dashboard`. `trigger` is a string taxonomy ("wi_parked" now; "decision_pending" / "slice_done" / "deliverable_review" added by later WIs). `route` is the app path the row links to. - Regenerate stubs after the proto edit: Rust via the build, PWA via `npm run generate` in `anima-pwa/` — committed `src/gen/*` must be regenerated and reconciled (see the PWA codegen-drift convention; stale gen masks drift). - `crates/anima-server/src/services/dashboard.rs` — in `build_dashboard`, add a query for parked WIs (RBAC-scoped) and map them to `AttentionItem { trigger: "wi_parked", route: "/work-items/<id>" (match the PWA's actual WI route), reason: "parked — needs you", occurred_at: updated_at }`. Add a `WorkItemRepo` query if needed (`crates/anima-db/src/repo/workitem.rs`). PWA: - `anima-pwa/src/pages/Dashboard/Dashboard.tsx` — remove the "Recent Activity" `<section>` (~lines 180-208) and its `listActivity` usage; add an **Inbox** section as the first child (above Runner Fleet). Source rows from `getDashboard().attentionInbox` (extend the dashboard fetch in `anima-pwa/src/lib/grpcApi.ts` — `getFleet` already calls `dashboardClient.getDashboard({})`; add an `attention_inbox` mapping rather than a second round-trip). - New component `anima-pwa/src/pages/Dashboard/AttentionInbox.tsx` (+ a `Row`): per-trigger icon/colour (only `wi_parked` now, but switch on `trigger` so later WIs slot in), title, reason, relative age, whole row is a `<Link to={route}>`. Empty state: "Inbox zero — nothing needs you." - Working UI label: "Inbox" (final label still open — keep it a single constant so it's trivial to change). - Keep mock parity: `anima-pwa/src/lib/mockApi.ts` + `mockData.ts` should return a couple of `attentionInbox` fixtures so tests + mock mode render. ## Acceptance criteria - [ ] `AttentionItem` + `Dashboard.attention_inbox` added to the proto; Rust + PWA stubs regenerated and committed. - [ ] `build_dashboard` returns parked WIs as `attention_inbox` items, scoped to the caller's RBAC projects (a user with no role on a project does NOT see its parked WIs). - [ ] Dashboard renders an Inbox section above Runner Fleet; each parked WI is a row that routes to the WI; un-parked WIs no longer appear. - [ ] The old "Recent Activity" section and its `listActivity` call are removed from the dashboard. - [ ] Empty state renders when there are no items. - [ ] `cargo check -p anima-server -p anima-db` clean; `npm run verify` green (a Dashboard/AttentionInbox test asserts a parked row renders + routes). ## Blocked by - None — can start immediately.
toasterson force-pushed claude/wi-019f1777-attention-inbox-end-to-end-wi-parked-tri from 7d3bd095b0 to e892c69de1 2026-07-04 23:41:41 +00:00 Compare
toasterson force-pushed claude/wi-019f1777-attention-inbox-end-to-end-wi-parked-tri from e892c69de1 to 0ed58ff9f0 2026-07-05 23:23:46 +00:00 Compare
toasterson force-pushed claude/wi-019f1777-attention-inbox-end-to-end-wi-parked-tri from 0ed58ff9f0 to 4254c8fa74 2026-07-06 00:12:37 +00:00 Compare
toasterson force-pushed claude/wi-019f1777-attention-inbox-end-to-end-wi-parked-tri from 4254c8fa74 to d033ef841d 2026-07-06 14:21:07 +00:00 Compare
toasterson force-pushed claude/wi-019f1777-attention-inbox-end-to-end-wi-parked-tri from d033ef841d to d3cc8ef059 2026-07-06 15:46:22 +00:00 Compare
Author
Owner

Subsumed by #287 and merged at ae5d72d. Your WI-parked trigger is included in #287's full inbox trigger set; the four inbox PRs were parallel implementations of the same feature, so the superset (#287) landed. WI marked done. Closing.

Subsumed by #287 and merged at `ae5d72d`. Your WI-parked trigger is included in #287's full inbox trigger set; the four inbox PRs were parallel implementations of the same feature, so the superset (#287) landed. WI marked done. Closing.
toasterson closed this pull request 2026-07-09 17:54:42 +00:00

Pull request closed

Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
toasterson/Anima!284
No description provided.