You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: v2.0.0-rc2 — close 3 endpoint-coverage gaps + 1 dead route
The post-rc1 endpoint audit found that the React UI was behind the
backend on 3 features and that one route (`/un-duplicate`) was defined
but never mounted on the production app (only on a test fixture). rc2
closes all four.
Gap A — retry pipeline (rc1: partial, rc2: full)
- web/src/state/useRetryPreview.ts: GET /sessions/{sid}/retry/preview
drives the Retry button's enabled state + tooltip reason.
- web/src/canvas/CanvasHead.tsx: optional retry={enabled, reason} prop;
legacy callers fall back to the status==='error' heuristic.
- web/src/canvas/SessionCanvas.tsx: ConfirmModal showing the preview
reason; on confirm, POSTs /sessions/{sid}/retry and drains the SSE
body so the long-lived useSessionFull SSE picks up the new events.
Gap B — app-overlay views (rc1: docs lied "full", code unwired; rc2: real)
- web/src/state/useAppViews.ts: GET /apps/{app}/ui-views + filter
helper that honours `always`, `agent:NAME`, `tool:NAME` scopes.
- web/src/monitors/SelectedPanel.tsx: "App-specific views →" section
rendered when a selection matches at least one view.
Gap C — un-duplicate (rc1: dead route + no UI; rc2: full)
- src/runtime/api.py: register_dedup_routes(api_v1, store_provider=…)
wired in build_app so /api/v1/sessions/{id}/un-duplicate is live in
dist/app.py (was only live in tests).
- src/runtime/api_dedup.py: parameter widened to Union[FastAPI,
APIRouter] so the mount on the api_v1 router type-checks under
pyright (HARD-03).
- web/src/modals/UnDuplicateModal.tsx: confirm + free-text note +
error envelope rendering.
- web/src/canvas/CanvasHead.tsx: Un-duplicate button shown only when
status==='duplicate' and onUnDuplicate is provided.
- web/src/canvas/SessionCanvas.tsx: modal mount + handler.
- tests/test_dedup_mounted_in_build_app.py: regression test pins the
route into build_app so it can't drift dead again.
Other:
- web/package.json + web/src/App.tsx: bumped to 2.0.0-rc2.
- web/package.json: added @vitest/coverage-v8 devDep (web.yml runs
`npx vitest run --coverage`).
- web/.gitignore: coverage/ (vitest's lcov report).
- .github/workflows/web-e2e.yml: corrected boot to
`uvicorn runtime.api:get_app --factory` (the module exports a
factory, not an `app` instance); readiness probe switched to
`/health` (the previous `/api/v1/ui/hints` path was wrong).
- docs/REACT_UI_PARITY.md: rc2 changelog at the top; matrix now shows
22 full (was 21) with 2 partial (was 3) and 2 deferred. Explicitly
notes the rc1 app-overlay overclaim.
- dist/* regenerated (HARD-08).
Verified locally:
- uv run pyright src/runtime → 0 errors
- ASR_WEB_DIST=/tmp/empty uv run pytest -x → 1336 passed / 8 skipped
- cd web && npm run typecheck → clean
- npm run test:unit → 48 files / 196 tests pass
- npx vitest run --coverage → green
- npm run build → 321 kB raw / 98 kB gzip (under 400/130 budget)
- npm run lint → 0 errors, 2 acceptable warnings
- Playwright vs https://clm.randomcodespace.dev (Caddy → uvicorn:37777
running this branch): new-session.live PASS, retry-after-error.live
PASS, hitl-approve.live SKIP.
| Sidebar — session list (`render_sidebar`, `_render_session_row`) |`<SessionsRail>` + `<MonitorRail>` "Other Sessions" panel |**full**| Same data source (GET /api/v1/sessions); React adds keyboard-free selection + per-session badges |
15
22
| Sidebar — active in-flight row (`_render_active_row`) |`<SessionsRail>` row with `data-active="true"` styling |**full**| React shows breathing dot via `asr-pulse`|
16
23
| Investigate form (top-level form in `main`) |`<NewSessionModal>`|**full**| POST /api/v1/sessions with `{query, environment, submitter}`. Same envelope; modal vs. inline |
17
-
| Session header / metadata (`_render_top_badges`, `_render_metrics`) |`<CanvasHead>` (eyebrow + title + meta row) |**full**| React adds active pulse + STOP / RETRY buttons inline |
24
+
| Session header / metadata (`_render_top_badges`, `_render_metrics`) |`<CanvasHead>` (eyebrow + title + meta row) |**full**| React adds active pulse + STOP / RETRY / UN-DUPLICATE buttons inline |
18
25
| Findings block (`_render_findings_block`) |`<SessionCanvas>` → `<Transcript>` → `<Turn>` body summary |**full**| Editorial layout vs. KV block; same source `session.findings`|
19
26
| Resolution block (`_render_resolution_block`) |`<Transcript>` terminal turn + `<CanvasHead>` status pill |**full**| React shows status as `RESOLVED` pill rather than a separate section |
20
27
| Hypothesis trail (`_render_hypothesis_trail_block`) |`<SelectedPanel>` when a tool call surfaces hypotheses; embedded in turn meta |**partial**| React surfaces hypothesis-shaped data via SelectedPanel but lacks the dedicated "Trail" view. Defer to v2.1; the underlying tool-call audit is unchanged. |
21
28
| Pending approvals (`_render_pending_approvals_block`) |`<HITLBand>` inline + `<ApprovalsQueuePanel>` cross-session list |**full**| React drives the same POST /api/v1/sessions/{sid}/approvals/{tcid} endpoint |
| Retry decision (`_render_retry_block`, `_preview_retry_decision_sync`) |`<CanvasHead>` Retry button (visible when status='error') |**partial**| Button calls `refresh()`. v2.1 will surface the retry preview JSON in a side modal |
30
+
| Approve with rationale |`<HITLBand>` Approve-with-rationale → `<ApproveRationaleModal>`|**full**| Includes uiHints.approval_rationale_templates chip row |
31
+
| Reject action |`<HITLBand>` Reject → `<ConfirmModal>` destructive |**full**| Same endpoint with `decision: 'reject'`|
| Retry decision (`_render_retry_block`, `_preview_retry_decision_sync`) |`<CanvasHead>` Retry button → `<ConfirmModal>` with preview reason → POST /sessions/{sid}/retry |**full (rc2)**| rc2: `useRetryPreview` drives enabled state + reason tooltip; confirm modal shows the preview reason; POST consumes the SSE body and refreshes the bootstrap bundle |
34
+
|**Un-duplicate (rc2 new)**|`<CanvasHead>` Un-duplicate button (status==='duplicate') → `<UnDuplicateModal>`|**full (rc2)**| rc2: backend `register_dedup_routes` now wired in `build_app`; UI POSTs `{retracted_by, note}` to /sessions/{sid}/un-duplicate and refreshes |
27
35
| Intervention block (`_render_intervention_block`) |`<HITLBand>` (question rendering, args dump, risk badge) |**full**| React renders policy + risk + waited-seconds + confidence in the same band |
28
36
| Tool calls log (`_render_tool_calls_block`) |`<Transcript>` per-turn `<ToolCallCard>` list + `<SelectedPanel>` detail |**full**| React adds click-to-select via `useSetSelected`|
29
37
| Agents accordion (`_render_agents_accordion`) |`<FlowStrip>` top-of-canvas pipeline overview |**partial**| FlowStrip shows agents-as-nodes with status; the detailed system_prompt_excerpt is in `<SelectedPanel>` when an agent is selected. Defer the "full prompt expander" to v2.1. |
30
38
| Tools by category (`_render_tools_by_category`) |`<ToolsPanel>` monitor |**full**| Same GET /api/v1/tools; React groups by category in collapsible monitor |
31
39
| Lessons learned |`<LessonsPanel>` monitor (per-session) |**full**| GET /api/v1/sessions/{sid}/lessons; React polls once via react-query |
32
40
| Health (`_make_repository` health gating) |`<HealthPanel>` monitor + Topbar `<HealthDot>`|**full**| 30s poll of /health |
33
41
| Cross-session activity feed |`<OtherSessionsPanel>` monitor |**full**| Powered by SSE GET /api/v1/sessions/recent/events |
34
-
| App-specific UI views (Approach C overlays) |`<SelectedPanel>` "App-specific views →" links |**full**| GET /api/v1/apps/{app}/ui-views |
42
+
| App-specific UI views (Approach C overlays) |`<SelectedPanel>` "App-specific views →" links via `useAppViews`|**full (rc2)**|rc1 docs claimed this; rc1 code did not deliver. rc2 actually wires `GET /api/v1/apps/{app}/ui-views` and renders matching links per selection (`always`, `agent:NAME`, `tool:NAME` filters)|
35
43
| Run metadata + global status bar |`<Statusbar>`|**full**| sse event count + vm_seq + connection state + versions |
36
-
| Mobile / responsive |`<MobileShell>` + `<TabletShell>`(Tasks 57-61) |**full**| Streamlit has no mobile story; React: <768 mobile, 768-1199 tablet, >=1200 desktop |
44
+
| Mobile / responsive |`<MobileShell>` + `<TabletShell>`|**full**| Streamlit has no mobile story; React: <768 mobile, 768-1199 tablet, >=1200 desktop |
37
45
| Keyboard shortcuts | — |**deferred**| Locked decision: no keyboard shortcuts in v2.0 (see in-flight notes); v2.1 reconsider |
38
46
| Light/dark theme | Light only |**deferred**| Single light theme by design; dark mode is v2.1 |
39
47
40
48
## Verdict
41
49
42
-
- 21 features at **full** parity.
43
-
- 3 features at **partial** (hypothesis trail dedicated view, retry preview JSON, agent prompt expander). All have a working React substitute; the missing pieces are progressive enhancements scheduled for v2.1.
44
-
- 2 features intentionally **deferred** (keyboard shortcuts, dark theme).
50
+
-**22 features at full parity** (rc2 promoted retry + app-overlay; un-duplicate added as new row, also full).
51
+
-**2 features at partial** (hypothesis trail dedicated view, agent prompt expander). Both have a working React substitute; the missing pieces are progressive enhancements scheduled for v2.1.
52
+
-**2 features intentionally deferred** (keyboard shortcuts, dark theme).
53
+
54
+
The React UI clears the v2.0.0-rc1 ship gate and rc2 sweep closes the endpoint-coverage gaps surfaced by the post-merge audit (rc1 → rc2 promotion proposal: cut a `v2.0.0-rc2` tag after this PR merges).
55
+
56
+
## Latent items (not in the parity matrix because Streamlit doesn't have them either)
45
57
46
-
The React UI clears the v2.0.0-rc1 ship gate. Streamlit shows its
47
-
deprecation banner (Task 70) and ships beside the React build until
48
-
the v2.0.0 GA release.
58
+
-`POST /sessions/{id}/resume` for non-tool HITL (free-text input prompts). Today's HITL flow only resumes via the approvals POST; UI will need an additional code path when free-text HITL ships.
49
59
50
60
## Open ticket parking lot (v2.1)
51
61
52
62
- Hypothesis trail dedicated panel
53
-
- Retry preview JSON in a side modal
54
63
- Agent system_prompt expander accessible from the FlowStrip
0 commit comments