Adds a one-click 'reset agents' action for cases where writer/QA agents
are stuck in Paperclip's error state (triggered by recovery loop or
failed run). Addresses the root cause documented in
reference_paperclip_recovery_loops: reassigns open issues from agents
back to the chair user, and calls reset_agent_session for each error
agent to clear wedged runtime sessions.
Changes:
- paperclip_client.py: reset_case_agents() — reassigns stuck issues +
clears error status in Paperclip DB + calls reset_agent_session
- agent_platform_port.py: exports pc_reset_case_agents (G12 gate)
- app.py: POST /api/cases/{case_number}/agents/reset endpoint
- agents.ts: useResetCaseAgents mutation hook + AgentResetResult type
- agent-status-widget.tsx: 'אפס' button (shown only when error agents
exist) with Dialog confirmation + loading state + toast feedback
Invariants: G12 (Paperclip only via port), G2 (no parallel path —
uses existing reset_agent_session + pc_get_case_issues).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Full code review of the case-detail page (14 components) surfaced these,
all fixed here:
Logic bugs
- case-edit-dialog: form.reset ran on the 5s useCase refetch while the dialog
was open, clobbering in-progress edits. Now resets only on open→true.
- status-changer: `selected` never synced to async/external `currentStatus`
(stale dropdown). Reworked to track currentStatus until an explicit pick;
resets to tracking after save.
- decision-blocks-panel: `block.content`/`word_count` accessed without null
guards (endpoint has no response model) → potential render crash. Coerced
with `?? ""` / `?? 0`. `STATUS_LABELS[status]` now falls back to the raw
status instead of rendering literal "undefined".
- document-type-editor: `await mutateAsync()` in async click handlers without
try/catch → unhandled promise rejection. Wrapped (errors still surface via
isError).
Resilience / hygiene
- page.tsx: a transient 5xx on the background poll flipped the WHOLE page to
the error card and discarded loaded data. Now gated on `!data`, plus a
"נסה שוב" retry.
- cases.ts useUpdateCase: invalidated casesKeys.all, which re-invalidated the
detail it had just optimistically patched. Scoped to the list prefix.
RTL correctness (logical properties)
- agent-status-widget `mr-auto`→`ms-auto`; agent-activity-feed `mr-auto`→
`me-auto`, icon `ml-1/ml-2`→`me-1/me-2`, required `*` `mr-1`→`ms-1`;
document-type-editor list `pr-4`→`ps-4`.
Minors
- drafts-panel: `<a href>`→`next/link` (operations + citation links) for SPA
nav. agent-activity-feed: issueMap memoized; comment Textarea aria-label.
upload-sheet: `unknown` status no longer shown as green success (neutral
icon + "רענן לאישור"). citations.ts: case_name typed `string | null`.
Design gate: visual-touching items (RTL gap side, retry button, neutral
upload icon) were chair-authorized via the reviewed-findings approval ("fix
all"); none alter an approved page layout — they are correctness fixes.
tsc clean; eslint clean (1 pre-existing form.watch warning, untouched line).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ממצא: התוכנית המקורית (namespace ל-paperclip.* ב-types.ts) בלתי-ישימה — types.ts
נוצר-אוטומטית מ-OpenAPI ("Do not make direct changes"); הפניות-Paperclip שם רק משקפות
את ה-API של ה-backend, ונשלטות ע"י מודלי-ה-Pydantic, לא ע"י הפרונט. הפרונט אינו
שכבת-אינטליגנציה — הפניות-Paperclip בו הן הצגת-נתוני-פלטפורמה (activity feed, קישור
לדאשבורד, סטטוס-ארכוב) או UI-ניהול מוצהר (paperclip-tab/agents-tab) — כולן shell-adjacent
לגיטימי תחת G12.
הבעיה האמיתית-והישימה: התנגשות-שם — `PaperclipAgent` הוגדר פעמיים עם shapes שונים
(config ב-paperclip-agents.ts מול activity ב-agents.ts). פוצל: ה-activity-DTO →
`PaperclipAgentStatus`; ה-config שומר `PaperclipAgent`. + הערת-כותרת שמסמנת את agents.ts
כמודול הצגת-פלטפורמה מוצהר.
מזין את R4 (#113): leak-guard חייב להחריג קבצים-נוצרים (types.ts) ולא לכלול את הפרונט
בהיקף שכבת-האינטליגנציה המוגנת.
אימות: tsc --noEmit נקי; eslint נקי על הקבצים ששונו.
Invariants: G12 (גבול-פלטפורמה מוצהר בפרונט), G2 (הסרת שם-טיפוס כפול-משמעות).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Agent status widget now checks heartbeat_runs + wakeup_requests to determine
if an agent is running on *this* case. Agents running on other cases show as idle.
Added "running" to STATUS_DOT/STATUS_LABEL maps so it displays in Hebrew.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New "Agents" tab in case detail shows all Paperclip agent comments,
issue status, and agent status for each case — eliminating the need
to switch between Legal-AI and Paperclip UIs.
Backend: 4 new DB query functions in paperclip_client.py (issues,
comments, agents, post_comment) + 2 new API endpoints (GET/POST
/api/cases/{case_number}/agents). Comment posting uses Board API
with DB+wakeup fallback to ensure CEO routing.
Frontend: agents.ts hooks (10s polling), AgentActivityFeed component
(markdown timeline + comment input), AgentStatusWidget (sidebar),
4th tab in case detail page.
Also includes new-company-setup-guide.md documenting the process
for setting up the betterment levy (CMPA) company.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>