feat(mobile): Tasks + Approvals inbox — decision-on-the-go (core#2697 Phase 1) #2765
Reference in New Issue
Block a user
Delete Branch "feat/mobile-inbox-tasks-approvals"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Phase 1 of the mobile user-flow alignment — the #1 gap
The desktop home flow has Tasks + Approvals as first-class destinations (ConciergeShell sidebar /
RequestsInbox). Mobile had no way to review or action pending requests — approve/reject-on-the-go, the canonical mobile job, was missing.What
A new 5th Inbox bottom tab →
MobileInbox, a mobile-native screen (not the desktop component crammed in) reusing the exact data layer the desktop uses:GET /requests/pending?kind=task|approvalto loadPOST /requests/{id}/respond {action, responder_type, responder_id}to decideREQUEST_*, session-derivedresponder_id.More-Info threads stay desktop-only for v1 (flagged in-code).
Placement
5th tab is the most faithful mobile analog of the desktop's peer-to-Agents home destinations (Agents ∣ Tasks ∣ Approvals); trivially movable to a header affordance if preferred — happy to adjust.
Tests / CI
MobileInbox.test.tsx(load / approve→respond+drop-row / empty);TabBar.test.tsxupdated for the 5-tab set. Full mobile suite green (253), in the blocking canvas vitest gate.🤖 Generated with Claude Code
APPROVED on head
d12b88e0.5-axis review:
MobileInboxreuses the same RequestsInbox data contract:GET /requests/pending?kind=task|approvalandPOST /requests/{id}/respondwith{action, responder_type, responder_id}. Approval/task actions map toapproved/done/rejected, matching the server and desktop component.REQUEST_*WS refresh is wired through the shared socket event hook. More-Info being deferred for mobile v1 is acceptable and called out in code/body.Verified current head is open/mergeable and
CI/all-requiredis green. /sop-ackPost-merge audit on merged head
d12b88e0(the PR merged while I was reviewing, so the formal review endpoint is closed).I found a decision-flow correctness issue in
MobileInbox: switching between Approvals and Tasks keeps the previous tab's rows rendered until the newGET /requests/pending?kind=...resolves.load()setsloading=truebut does not clear or partitionitems(canvas/src/components/mobile/MobileInbox.tsx:48-55), and the primary action derives from the current tab state rather than the row kind (MobileInbox.tsx:171-172).Failure path:
items.MobileInbox.tsx:115). Before the task fetch resolves, the approval rows remain visible, now underkind === "task".Done, and tapping it postsaction: "done"for an approval request via/requests/{id}/respond.That violates the approve/reject safety requirement: an approval can be accidentally completed with the task action during a tab transition. Desktop avoids this class by mounting separate
RequestsInbox kind="task"andRequestsInbox kind="approval"instances, keeping each list scoped to its kind.Recommended follow-up: clear or key rows by kind on tab switch/load, and/or derive render/actions from
r.kindinstead of selected tab state. Add a regression test with a delayed second tab fetch proving stale approval rows cannot be actioned as tasks during the transition.CI note: code CI/all-required and Canvas CI were green; this is a functional post-merge audit finding.