CI surfaced react-hooks/set-state-in-effect on the synchronous setState(computeState(token)) inside the useEffect body. The earlier shape mirrored token -> state via an effect, which is exactly the "you might not need an effect" pattern React 19's eslint rule now flags. Switch to derived state: compute during render, use a useReducer tick to force re-render on the 30s cadence (so relative timestamps stay current even when token props don't change). Same observable behavior, no cascading renders. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2.3 KiB
2.3 KiB
Test Plan
Generated by /plan-eng-review on 2026-04-27 Branch: main Repo: chihlasm/resolutionflow
Affected Pages/Routes
/escalations(EscalationQueuePage.tsx) — senior-tech inbox view; verify queue list, real-time arrival, click-through/pilot/:session_id(FlowPilotSessionPage) — verify post-claim load shows full escalation context (snapshot, ai_assessment, escalation_package)GET /api/v1/analytics/escalation-metrics(NEW) — verify hero metric calculation, account-scoping, role gate
Key Interactions to Verify
- Junior tech clicks Escalate in active FlowPilot session → handoff is created → notification fires → senior sees escalation in queue within 30 seconds
- Senior tech clicks Claim in queue → session reactivates → senior is redirected into FlowPilot session view → ai_assessment + snapshot are visible
- Senior types first message in chat after claim → metric query starts attributing time-to-first-action
- MSP owner opens analytics page → "minutes recovered per escalation" widget shows current month's rolling average
Edge Cases
- Two seniors race to claim the same handoff → one wins, the other gets a "Already claimed by [name]" message
- Senior is offline when escalation fires → email arrives via existing
EmailService.send_notification_email - WebSocket disconnects mid-session → frontend reconnects; missed events backfilled by re-fetching the queue
- Notification dispatch raises (SMTP down, WebSocket fanout fails) → handoff is still created (graceful degradation)
- Senior takes non-chat action first (e.g., posts directly to PSA) → metric falls back to PSA writeback timestamp or remains null; doc the chosen behavior
- Account-scoped multi-tenancy → senior at MSP A cannot see escalations from MSP B (Phase 4 RLS)
- Role gate on metric endpoint → only
engineer_or_admincan hit/escalation-metrics
Critical Paths
- Magic-moment demo flow (the entire Loom): junior escalate → senior notification → senior claim → session view → first action recorded → metric updates
- Email fallback when senior is offline — must not silently drop
- Regression: handoff creation succeeds even if notification dispatch raises — graceful degradation is mandatory