feat(v1.1/W4): write-paths + SSE wired#8
Conversation
…21) / audit replay / breaker reset / live-feed
Wires every non-GET admin surface against the live host backend. The
prototype's synthetic live-feed simulator is retired in favour of a
real subscribeEvents() consumer.
Surfaces wired (all 5 from the W4 checklist):
- ServersListPage bulk-bar: useDeleteServer / useUpdateServer /
useHandshake. Promise.allSettled fan-out surfaces partial failures
as a single toast. Optimistic selection clear on delete confirm.
- ServerDetailPage: handshake / enable-disable / delete actions
call real mutations (server-detail-{action} testids).
- ServerNewPage: wizard submit calls useCreateServer; wire payload
drops fields the BE doesn't yet accept. ValidationError jumps the
wizard back to the step owning the failing field + inline error.
- ToolPlayground: useInvokeTool with R21 two-call confirm-token
protocol — first POST no token, on 202 the playground opens a
TypeToConfirmModal (phrase invoke-{toolName}), second POST uses
ONLY the server-minted token. ValidationError surfaces inline.
- AuditDrilldown replay: same R21 two-call protocol.
- BreakersPage reset: same R21 protocol with a confirm-mode flip
(simple Modal first-leg → TypeToConfirmModal second-leg).
- App.tsx live-feed: subscribeEvents() with paused-via-ref so the
EventSource stays open during pause/resume; events deduped by id.
Cross-cutting invariants:
- R14 — every mutation surfaces failures via toast; ValidationError
pins field-level errors; AuthExpiredError still fires the existing
global auth:expired event (unchanged).
- R21 — destructive mutations strictly use two-call protocol with
server-minted tokens.
- R11 / R29 — stable testids on every new action button + modal.
Test coverage (+21 specs across 5 files, 132→153 total, all green):
- tests/js/pages/servers-mutations.test.tsx
- tests/js/pages/tools-invoke.test.tsx
- tests/js/pages/audit-replay.test.tsx
- tests/js/pages/breakers-reset.test.tsx
- tests/js/pages/dashboard-sse.test.tsx
Excluded from W4 (carried to v1.2): SettingsPage API-keys wiring;
E2E Playwright fixture-drift cleanup (W5 scope).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
W4 of the v1.1 milestone: wires every non-GET admin surface in the SPA to real mutation hooks against the host backend, and replaces the prototype's synthetic live-feed simulator with a real subscribeEvents() EventSource consumer.
Changes:
- Wires bulk + per-row server mutations (CRUD/handshake) on
ServersListPage/ServerDetailPage/ServerNewPage, surfacing partial failures viaPromise.allSettledand field-levelValidationErrorinline. - Implements R21 two-call confirm-token protocol for tool invoke (
ToolPlayground), audit replay (AuditDrilldown) and breaker reset (BreakersPage) usingConfirmTokenError.confirmTokenMintandTypeToConfirmModal. - Replaces the
setIntervallive-feed simulator inApp.tsxwith a singlesubscribeEvents()subscription, using alivePausedRefso Pause/Resume drops events without reconnecting, dedupes by id, capped to 200.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| resources/js/App.tsx | Replaces the synthetic live-feed simulator with an SSE subscription and pause-without-reconnect ref. |
| resources/js/pages/servers.tsx | Wires bulk + detail + wizard mutations with toast/field-error surfaces and new testids. |
| resources/js/pages/tools.tsx | Wires useInvokeTool with R21 two-call protocol and inline ValidationError rendering. |
| resources/js/pages/audit.tsx | Wires useReplayAudit and useResetBreaker with the R21 two-call confirm-token protocol. |
| tests/js/pages/servers-mutations.test.tsx | New page-level coverage for bulk + detail + wizard mutation flows. |
| tests/js/pages/tools-invoke.test.tsx | New coverage for the R21 two-call protocol + 422 validation in the playground. |
| tests/js/pages/audit-replay.test.tsx | New coverage for replay R21 protocol + success/failure toasts. |
| tests/js/pages/breakers-reset.test.tsx | New coverage for breaker reset 200/202+token/500 paths. |
| tests/js/pages/dashboard-sse.test.tsx | New coverage shim for SSE consumer (dispatch, dedupe, pause, teardown). |
| CHANGELOG.md | Documents the W4 wave (write paths + SSE) under the v1.1.0 Unreleased section. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2022280397
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (err instanceof ConfirmTokenError) { | ||
| // R21 first leg: open confirm modal with the server-minted token. | ||
| setPendingConfirm({ | ||
| token: err.confirmTokenMint?.confirm_token, | ||
| expires_in: err.confirmTokenMint?.expires_in, | ||
| reason: err.reason, | ||
| }); |
There was a problem hiding this comment.
Treat expired confirmation tokens as failures
When the second-leg invoke request returns a ConfirmTokenError because the minted token expired or was invalid, confirmTokenMint is null, but this branch still reopens the confirm modal and stores an undefined token. In the scenario where an operator waits past expires_in before confirming, the retry sends no token and loops back through the same path instead of surfacing the backend error; only open the modal when a fresh confirmTokenMint.confirm_token is present and otherwise show the failure toast.
Useful? React with 👍 / 👎.
…r without fresh mint When the second-leg invoke/replay/reset call ALSO throws ConfirmTokenError (operator waited past expires_in → server rejected stale token), the original code unconditionally re-opened the confirm modal with err.confirmTokenMint?.confirm_token (which may be null), creating an infinite re-confirm loop with an undefined token. Fix in 3 places: if confirmToken was already supplied AND the new error doesn't carry a fresh mint, surface a hard failure toast (plus inline error response in ToolPlayground) telling the operator to start a new confirmation; do NOT reopen the modal. First-leg path is unchanged. New spec: tests/js/pages/tools-invoke.test.tsx: "second-leg ConfirmTokenError without fresh mint surfaces hard failure (no infinite loop)" Asserts calls.length === 2 after expired-token rejection. Vitest: 154/154 green (132 from W3 + 21 from W4 initial + 1 new).
|
@copilot review |
Summary
Wires every non-GET admin surface in the SPA to real mutation hooks
against the host backend, and replaces the prototype's synthetic
live-feed simulator with a real
subscribeEvents()EventSourceconsumer.
Surfaces wired (5/5 from W4 checklist)
ServersListPagebulk-bar (delete / enable /disable / handshake),
ServerDetailPageaction header(handshake / toggle-enabled / delete),
ServerNewPagewizardsubmit.
Promise.allSettledfan-out surfaces partial failures asmixed toasts.
ToolPlaygroundcallsuseInvokeToolwiththe two-call confirm-token protocol: first POST without a token,
202 →
TypeToConfirmModal(invoke-{toolName}), second POST withthe server-minted token.
ValidationErrorsurfaces inline underthe args form.
AuditDrilldownReplay button uses thesame two-call protocol on
useReplayAudit.BreakersPagereset uses a confirm-modeflip (simple
Modalfor first-leg,TypeToConfirmModalif the BEreturns 202 with a minted token).
App.tsxretires thesetIntervalsimulatorin favour of
subscribeEvents(). AlivePausedReflets thePause/Resume toggle drop events WITHOUT reconnecting. Events are
deduped by id (R25 spirit), buffer capped at 200.
Cross-cutting invariants
ValidationError errors appear next to inputs.
token from
ConfirmTokenError.confirmTokenMint. Clients neverinvent tokens.
servers-bulk-{action},server-detail-{action},servers-new-submit,tools-playground-invoke,tools-playground-field-errors,audit-drilldown-replay,breakers-reset-confirm.Test plan
npm test— 153 specs green (132 baseline + 21 new across 5files:
servers-mutations,tools-invoke,audit-replay,breakers-reset,dashboard-sse).inline error.
auth:expiredevent.(token absent on first call, present on second).
teardown.
CI expectation
Playwright fixture-drift between the SPA's wire expectations and
the real
mcp-packv1.4 endpoint shapes continues. That cleanupis the W5 scope; page-level Vitest coverage locks in the R21 + R14
invariants in the meantime.
Excluded from this wave (carried to v1.2)
useCreateApiKey/useRevokeApiKeyhooks exist; UI wiring issmall enough to land standalone.
🤖 Generated with Claude Code