CedarCopilot wants to merge 2 commits into staging from fix/chat-tab-self-scope
Live on prod since Sat, 3 of 11 surfaces working
Libra measured 3 of 11 production surfaces on prod. 1 surface had under 20 requests, so Libra has not judged it; 7 surfaces had no requests at all. Libra checks hourly for 3 days after each deploy.
Follow-up to #2766. That PR closed the chat-thread cross-user IDOR but left agent.getRuns's Chats tab as a hardcoded stub ({ chats: [] }) with a comment claiming it was waiting on chat_threads.agent_id , a column that, per docs/agent-workspace.md's Phase 8, already existed and was fully wired everywhere else. Investigating why an org admin's report ("a teammate's chat silently fails to load") wasn't actually fixed by #2766 turned up two things:
agent.ts's getRuns unconditionally returned { executions: [], chats: [] } for kind: 'chats', and the frontend (AgentView.tsx) only ever queried kind: 'executions', so AgentRunsTab's chats prop was always undefined. Fixed: a new getAgentChats query (mirrors getAgentRuns's shape , one query for threads, one grouped follow-up for message counts, using the existing getPrimaryConversation helper for the subject binding) and a second useQuery in AgentView.tsx alongside the executions one, since the router answers one half of the union per kind.ChatRow's openChatThread ā store.switchThread ā loadThreadMessages ā chat.getMessages) has no concept of an admin-scoped viewing target anywhere in the store , it always loads by the session user's own id. Listing a teammate's chats in the tab would only produce a list that breaks the moment a row is clicked, recreating the original bug one layer deeper. So this PR scopes chats to SELF only, deliberately not admin-viewable:
authorize.ts's chat_thread:user policy tightened from SELF_OR_ORG_ADMIN (added in #2766) to SELF.agent.ts's getRuns guards the chats branch directly (actorUserId === ctx.sessionUser.id) since it resolves its actor through subagent_execution, not chat_thread , the policy table alone doesn't reach it.An org admin viewing a teammate's agent now sees an honest empty Chats tab instead of a broken one. Widening this back to admin-viewable is future work once the chat store carries a real viewing scope.
pnpm --filter @zero/server run types , cleanpnpm --filter @zero/mail run types , cleanchat-router-org-admin.test.ts , the four admin-CAN cases flipped to admin-CANNOT (SELF policy refuses everyone but the owner)agent-router-org-admin.test.ts , two new cases: an admin viewing a teammate's agent gets [] for chats even though the stub genuinely has a row for that thread (proves the guard fires, not that data happened to be absent); the teammate viewing their own agent still gets their real chats backagent-router-auth.test.ts , real coverage of getAgentChats's query + mapping (previously only exercised the vacuous empty-stub path)AgentRunsTab tests passš¤ Generated with Claude Code
https://claude.ai/code/session_0187itFj1uakga2xd7kPk4qp
This PR replaces the Agent Workspace Chats stub with real, owner-scoped chat history and narrows chat-thread authorization to self access until the embedded viewer supports administered-user scope.
agent.getRuns query and supplies chat summaries to the Previous Runs UI.The PR should not merge until conversation-scoped Chats results are restricted to the selected conversati
| Surface | Requests | Errors | p95 | Users | Verdict |
|---|---|---|---|---|---|
| orchestrator_agent_step | 52 ā 85 | 0 ā 0 (0%) | 251638 ms ā 163253 ms | 34 | Working 85 requests since the deploy with 0 errors (0 errors in the 52-request baseline before it). p95 163253 ms, was 251638 ms. |
| model_chunk On-Event Execution Agent (Understudy) | 35 ā 84 | 0 ā 0 (0%) | 5 ms ā 1 ms | 0 | Working 84 requests since the deploy with 0 errors (0 errors in the 35-request baseline before it). p95 1 ms, was 5 ms. |
| model_chunk Automation Agent (Understudy) | 26 ā 24 | 0 ā 0 (0%) | 3 ms ā 1 ms | 0 | Working 24 requests since the deploy with 0 errors (0 errors in the 26-request baseline before it). p95 1 ms, was 3 ms. |
| aws-primary.syncThread | 10 ā 4 | 7 ā 0 (0%) | 385 ms ā 535 ms | 0 | Insufficient traffic 4 requests, under the 20 Libra needs |
| model_chunk Automation Agent (Kimi K3 experiment) | 0 ā 0 | 0 ā 0 (0%) | not measured | 0 | No traffic No requests recorded since this deploy. |
| /api/trpc/agentExecutions.getAgentExecutions | 0 ā 0 | 0 ā 0 (0%) | not measured | 0 | No traffic No requests recorded since this deploy. |
| /api/trpc/agent.list | 0 ā 0 | 0 ā 0 (0%) | not measured | 0 | No traffic No requests recorded since this deploy. |
| /api/trpc/agent.getInvocationSources | 0 ā 0 | 0 ā 0 (0%) | not measured | 0 | No traffic No requests recorded since this deploy. |
| /api/trpc/settings.updateAgentSettings | 0 ā 0 | 0 ā 0 (0%) | not measured | 0 | No traffic No requests recorded since this deploy. |
| /api/trpc/agentExecutions.executeFromClientSend | 2 ā 0 | 0 ā 0 (0%) | 12935 ms ā not measured | 0 | No traffic No requests recorded since this deploy. |
| model_chunk Automation Agent (Sol experiment) | 0 ā 0 | 0 ā 0 (0%) | not measured | 0 | No traffic No requests recorded since this deploy. |