docs(ai): handoff state after bell-icon fix; record draft PR #155
All checks were successful
Mirror to GitHub / mirror (push) Successful in 4s
CI / frontend (pull_request) Successful in 5m41s
CI / backend (pull_request) Successful in 9m55s
CI / e2e (pull_request) Successful in 9m13s

Updates the handoff trio after the legacy notification flow fix and
the branch push. PR #155 is open against main as draft. Resume point
is now visual QA via /qa, then deferred follow-ups (chat-input
suggested-step chips, snapshot expansion). Logs the open question
about whether EscalateModal should switch to /handoff.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-04-27 21:33:44 -04:00
parent 641853a002
commit 2a2329ad19
3 changed files with 24 additions and 10 deletions

View File

@@ -2,11 +2,11 @@
# HANDOFF.md
**Last updated:** 2026-04-27 21:30 EDT
**Last updated:** 2026-04-27 21:50 EDT
**Active task:** **Escalation Mode** wedge build. See [`CURRENT_TASK.md`](CURRENT_TASK.md) for the full status; this file holds the resume point only.
**Branch:** `feat/escalation-metric-endpoint`frontend live-arrival SSE slice + magic-moment handoff-context screen are both shipped on top of the test-stabilized backend. Branch is unpushed.
**Branch:** `feat/escalation-metric-endpoint`pushed. **Draft PR #155** open against `main` ([gitea.resolutionflow.com/chihlasm/resolutionflow/pulls/155](https://gitea.resolutionflow.com/chihlasm/resolutionflow/pulls/155)). Wedge is feature-complete pending visual QA + the deferred follow-ups in `CURRENT_TASK.md`.
## Status
@@ -17,13 +17,16 @@ What landed (commits added to the branch):
- `b8627f4` feat(escalations): subscribe EscalationQueue to live SSE arrivals — `streamEscalations` in `aiSessions.ts` (fetch-based `ReadableStream` parser; native `EventSource` can't send auth headers); `HandoffCreatedEvent` + `EscalationStreamHandlers` types; `EscalationQueue.tsx` rewrite with `AbortController`-managed subscription, exponential-backoff reconnect (1s → 30s cap, resets on `ready`), prepend-on-arrival with locked 200ms slide-in, tab-title `(N)` prefix while `document.hidden`, `prefers-reduced-motion` swap, ARIA live region.
- `f65b657` docs(ai): handoff state after frontend SSE slice lands.
- `8e9d22e` feat(escalations): magic-moment handoff-context screen on pickup — new `HandoffContextScreen.tsx` (4 sections; renders gracefully when `ai_assessment` is null per the 5s timeout from `9bdd995`; ARIA dialog + focus on primary CTA + Esc dismiss for re-open overlay; `prefers-reduced-motion` honored). `FlowPilotSessionPage.tsx` integration: on `?pickup=true`, fetch the handoff list first (account-scoped via RLS, no claim required), find the latest unclaimed escalate handoff, render the screen and skip `loadSession` (senior would 404 pre-claim). "Start here" calls `claimHandoff`, drops the pickup query, and dismisses — `loadSession` then fires because senior is now `escalated_to_id`. Toolbar "Context" button on active sessions re-opens the screen as a dismissible overlay (visible only when senior arrived via the magic-moment flow this session).
- `c194ba4` docs(ai): handoff state after magic-moment screen lands.
- `641853a` fix(escalations): bell-icon notification opens the pickup flow — `_build_notification_link` for `session.escalated` now ends with `?pickup=true` so notification clicks route through the senior-pickup flow. `GET /ai-sessions/{id}` now allows account-scoped read for `requesting_escalation` / `escalated` status (RLS already enforces tenant boundary; the owner-only guard was overly restrictive for explicitly-shared in-transit states). Without these two fixes the user observed bell-icon clicks "just clearing the notification" — the navigation was happening but landing on a 404 the senior couldn't escape from.
Verified:
- `tsc -b` exit 0 after each commit.
- Backend regression: focused subset still `32 passed in 18.91s` with `-n auto`. No backend changes in this session.
- `tsc -b` exit 0 after each frontend commit.
- Backend regression with the access-policy change: focused subset + `test_sessions` + `test_session_sharing` `94 passed in 43.26s` with `-n auto`.
- Live SSE handshake against the running dev stack: 200 + `text/event-stream`; `ready` frame on connect; `handoff_created` frame with full payload arrived after posting a handoff via the API. Wire format matches the parser exactly.
- Live claim flow against the running dev stack: `listHandoffs` returns the unclaimed handoff for a senior pre-claim; `claimHandoff` flips session status from `escalated``active` and sets `escalated_to_id`; subsequent `GET /ai-sessions/{id}` succeeds.
- Live access-policy verification: senior (non-owner, non-target) can now `GET` an in-transit escalated session detail.
Not yet verified (would need a real browser session): the slide-in animation visually plays, tab title actually updates, reduced-motion media-query path renders, AbortController cleanup on unmount, exponential backoff after a real network blip, the magic-moment screen layout/typography looks right, dissolve transition feels right. Wire contract + integration semantics are confirmed; visuals are next.
@@ -31,9 +34,9 @@ Smoke-test artifact: a single test handoff (`0f6149db…` on session `50ea20d4
## Resume point
1. **Visual QA the two new frontend slices in a real browser.** Open `/escalations` as a senior, escalate from a separate session/tab, watch the slide-in + tab-title flash. Then click Pick Up and walk through the magic-moment screen → Start here → confirm the FlowPilot view loads cleanly. The `/qa` skill is the right tool.
2. **Push the branch and open a draft PR** against `main`. Title: "Escalation Mode wedge". Body: link the design + test-plan artifacts in `docs/plans/`.
3. **Pick up the deferred follow-ups** in `CURRENT_TASK.md` — the highest-leverage one is the suggested-step chips below the chat input (Codex correction, locked in design). The `HandoffManager._generate_snapshot` expansion to include recent steps/conversation is the next-highest leverage so the magic-moment screen can show the diagnostic timeline pre-claim.
1. **Visual QA via `/qa` against the dev stack.** End-to-end demo flow: junior escalates via EscalateModal → senior gets bell-icon notification → senior clicks the notification (now routes through `?pickup=true`) → magic-moment screen renders → Start here → FlowPilot session view loads. Also: open `/escalations` as senior with a second session escalating in the background, watch the slide-in + tab-title flash. The PR description has a checklist mirroring this.
2. **Pick up the deferred follow-ups** in `CURRENT_TASK.md`. Highest-leverage: suggested-step chips below the chat input (Codex correction, locked design — needs threading through `FlowPilotSession``FlowPilotMessageBar`). Next: `HandoffManager._generate_snapshot` expansion to include the recent diagnostic timeline pre-claim so the "What's been tried" section shows the actual conversation tail instead of a step-count affordance.
3. **EscalateModal currently uses the legacy `/escalate` endpoint, not `/handoff`.** That means the user's recent test went through the legacy notification path (which now works post `641853a`) rather than the new handoff/SSE flow. Wedge demo recording will be cleaner if EscalateModal is switched over — open question whether to do it as a parallel path (legacy escalate also creates a handoff) or a full migration (replace `/escalate` with `/handoff` + intent=escalate). Legacy path produces full PSA documentation push that the handoff path doesn't, so a parallel path is probably the right call for v1.
4. Optional v1: owner-facing `/analytics/escalations` page; Playwright e2e for the GTM Loom demo path.
## Useful breadcrumbs