docs(ai): refresh handoff for PR #156 — pending-verification feature
Closes out Escalation Mode (PR #155 merged) and pivots active task to the new applied_pending suggested-fix outcome on PR #156. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,55 +2,48 @@
|
||||
|
||||
# HANDOFF.md
|
||||
|
||||
**Last updated:** 2026-04-30 (Codex review-fix pass)
|
||||
**Last updated:** 2026-04-30 (session 4 — pending-verification feature shipped, PR #156 open)
|
||||
|
||||
**Active task:** **Escalation Mode** wedge — BROWSER QA COMPLETE + review fixes applied. Branch: `feat/escalation-metric-endpoint`. PR #155 ready to mark ready-for-review after committing this fix pass.
|
||||
**Active task:** Suggested-fix `applied_pending` outcome. Branch: `feat/fix-pending-verification` (1 commit, rebased onto main). PR #156 open, ready for browser QA.
|
||||
|
||||
**Just-merged:** PR #155 (Escalation Mode wedge) merged into main as `ac42f97`.
|
||||
|
||||
## Where this session ended
|
||||
|
||||
Code-review fixes were applied after browser QA:
|
||||
Single-PR cleanup pass after Escalation Mode browser QA, then a new feature.
|
||||
|
||||
- `claim_session` now uses atomic conditional `UPDATE ... WHERE claimed_by IS NULL` instead of read-then-write, so simultaneous senior pickup cannot silently overwrite `claimed_by`.
|
||||
- Original escalators cannot claim their own handoff. The escalation queue also excludes the current user's own escalated sessions, preventing the post-escalation dashboard from showing the junior their own handoff.
|
||||
- `session.escalation_package["handoff_id"]` is now populated from a preassigned UUID instead of `None` before flush.
|
||||
- Frontend build blockers removed: deleted unused legacy `claiming` / `handleStartHere` path in `AssistantChatPage` and unused `onStartHere` destructuring in `HandoffContextScreen`.
|
||||
1. **Codex review fixes on the escalation branch** committed as `f10649a` (atomic claim conditional UPDATE, self-claim 403 + queue self-exclusion, preassigned handoff UUID for the compatibility payload, removed legacy `claiming` / `handleStartHere` frontend dead code that broke `tsc --noEmit`).
|
||||
2. **PR #155 merged** to main via Gitea API (un-drafted, retitled, merged with a merge commit).
|
||||
3. **New branch `feat/fix-pending-verification`** off main, single commit `00663a4`. Adds `applied_pending` non-terminal status + `pending_reason` column + `PendingBanner` UI + 4 new integration tests. Rebased onto post-merge main.
|
||||
4. **PR #156 opened** for the new feature.
|
||||
5. **Cleanup:** 10 stray `core.*` dump files removed from the worktree; merged `feat/escalation-metric-endpoint` deleted locally and on the remote.
|
||||
|
||||
**Validation:**
|
||||
**Validation on PR #156:**
|
||||
|
||||
- `git diff --check` ✅
|
||||
- `cd backend && pytest --override-ini='addopts=' tests/test_handoff_manager.py tests/test_session_handoffs_api.py tests/test_escalation_bus.py` ✅ `28 passed in 42.23s`
|
||||
- `cd frontend && /config/.bun/bin/bunx tsc -p tsconfig.app.json --noEmit --pretty false && /config/.bun/bin/bunx tsc -p tsconfig.node.json --noEmit --pretty false` ✅
|
||||
- Full frontend build could not complete because generated dirs are root-owned in this workspace: `frontend/node_modules/.tmp`, `frontend/node_modules/.vite-temp`, and likely `frontend/dist` produce EACCES. Type errors from review are fixed.
|
||||
|
||||
**Not testable in dev (known limitations):**
|
||||
- "Continue where X left off": requires senior to have existing task lane for session (won't occur on first pickup)
|
||||
- Browser-level 409 race toast still requires two distinct senior accounts. Backend claim write is now atomic and covered by service/API tests for conflict, self-claim, and idempotent same-user retry.
|
||||
- `pytest tests/test_fix_outcome_endpoint.py` ✅ 21/21 pass (including 4 new pending tests).
|
||||
- `tsc --noEmit -p tsconfig.app.json` ✅ exit 0.
|
||||
- `alembic upgrade heads` ✅ ran `c0f3a4b7e91d` cleanly.
|
||||
|
||||
## Resume point — DO THIS NEXT
|
||||
|
||||
**Ship:** Commit this review-fix pass, then mark PR #155 ready-for-review and demo to stakeholder.
|
||||
|
||||
Optional before shipping:
|
||||
- Record Loom demo walking through the escalation flow end-to-end
|
||||
**Browser QA on PR #156** (see CURRENT_TASK.md "Resume point" for the 4-step checklist). Then merge.
|
||||
|
||||
## Key files changed this session
|
||||
|
||||
- `backend/app/services/handoff_manager.py` — `_generate_handoff_summary` replaces old assessment pair; `enrich_escalation_async` unified; `claim_session` eager-loads `handed_off_by_user`
|
||||
- `backend/app/api/endpoints/ai_sessions.py` — escalation queue excludes the current user's own escalations
|
||||
- `backend/app/api/endpoints/session_handoffs.py` — self-claim returns 403
|
||||
- `backend/app/services/flowpilot_engine.py` — `generate_status_update` early-returns saved prose for `context='escalation'`
|
||||
- `backend/app/schemas/session_handoff.py` — `handed_off_by_name: str | None = None` added
|
||||
- `backend/app/api/endpoints/session_handoffs.py` — both create + claim endpoints pass `handed_off_by_name`
|
||||
- `frontend/src/types/branching.ts` — `HandoffResponse` updated with `summary_prose`, `what_we_know`, `confidence: string`, `handed_off_by_name`
|
||||
- `frontend/src/components/flowpilot/HandoffContextScreen.tsx` — 3-option CTA; `hasTaskLane`, `activeOptionKey`, `onContinue/onAIAnalysis/onOwnThing` props
|
||||
- `frontend/src/components/assistant/TaskLane.tsx` — `id="task-lane-card-{idx}"` on all card variants
|
||||
- `frontend/src/pages/AssistantChatPage.tsx` — `handleContinue`, `handleAIAnalysis`, `handleOwnThing` handlers; chip → card navigation; `activeOptionKey` state
|
||||
- `backend/tests/test_handoff_manager.py`, `backend/tests/test_session_handoffs_api.py` — regression coverage for atomic/idempotent claim, self-claim rejection, queue self-exclusion, and pre-flush handoff ID
|
||||
- `backend/app/models/session_suggested_fix.py` — CHECK constraint extended; `pending_reason` Text column.
|
||||
- `backend/app/schemas/session_suggested_fix.py` — `applied_pending` added to both `FixStatus` and `FixOutcome` literals; `pending_reason` on response model; updated docstring on `SessionSuggestedFixOutcomeRequest`.
|
||||
- `backend/alembic/versions/71efd2102f49_add_pending_status_to_suggested_fixes.py` — new migration (rev `c0f3a4b7e91d`, down `71efd2102f49`).
|
||||
- `backend/app/api/endpoints/session_suggested_fixes.py` — `patch_outcome` accepts pending, requires notes, stamps applied_at only.
|
||||
- `backend/app/services/{resolution_note,escalation_package}_generator.py` — system-prompt handling for the new status; `pending_reason` line in input bundle.
|
||||
- `backend/tests/test_fix_outcome_endpoint.py` — 4 new tests.
|
||||
- `frontend/src/api/sessionSuggestedFixes.ts` — types updated; `pending_reason` on `SessionSuggestedFix`.
|
||||
- `frontend/src/components/pilot/ProposalBanner.tsx` — `'pending'` `BannerMode`; `PendingBanner` component; "Waiting to verify…" overflow option; nudge "Still checking" wired to record pending.
|
||||
- `frontend/src/pages/AssistantChatPage.tsx` — banner-mode derivation maps `applied_pending → 'pending'`.
|
||||
|
||||
## Watch-outs
|
||||
|
||||
- Dev stack: backend `:8000`, frontend `:5173`, postgres `:5433` (docker-compose). HMR works.
|
||||
- Test users (Acme MSP, password `TestPass123!`): `engineer@resolutionflow.example.com` (junior), `teamadmin@resolutionflow.example.com` (senior).
|
||||
- `handleAIAnalysis` pre-adds `urlSessionId` to `loadedChatIdsRef` before dismissing so the normal selectChat effect doesn't double-fire. It then calls `selectChat` manually before sending the briefing.
|
||||
- Legacy `claiming` / `handleStartHere` on `AssistantChatPage` was removed; `activeOptionKey !== null` is the active pre-claim processing signal.
|
||||
- The bus is acceptable for v1 pilot scale only (Railway single-replica). Redis pub/sub is the swap when horizontal scaling appears.
|
||||
- Test users (Acme MSP, password `TestPass123!`): `engineer@resolutionflow.example.com`, `teamadmin@resolutionflow.example.com`.
|
||||
- Multi-head alembic state on main is pre-existing (heads `070`, `c0f3a4b7e91d`, `024`); not introduced by this work but worth knowing if `alembic upgrade head` complains — use `upgrade heads` (plural).
|
||||
- `pending_reason` is preserved as audit trail when an engineer advances pending → success/failed/dismissed; it is not auto-cleared. Intentional.
|
||||
- Pre-existing local branches still in the working copy: `chore/post-153-handoff`, `feat/flowpilot-migration`, `fix/ci-*`, `fix/e2e-test-selectors` — left alone.
|
||||
|
||||
Reference in New Issue
Block a user