Skip to content

feat(v1.1/W4): write-paths + SSE wired#8

Merged
lopadova merged 2 commits into
mainfrom
feature/v1.1/W4-write-paths
May 18, 2026
Merged

feat(v1.1/W4): write-paths + SSE wired#8
lopadova merged 2 commits into
mainfrom
feature/v1.1/W4-write-paths

Conversation

@lopadova
Copy link
Copy Markdown
Contributor

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() EventSource
consumer.

Surfaces wired (5/5 from W4 checklist)

  • Server CRUDServersListPage bulk-bar (delete / enable /
    disable / handshake), ServerDetailPage action header
    (handshake / toggle-enabled / delete), ServerNewPage wizard
    submit. Promise.allSettled fan-out surfaces partial failures as
    mixed toasts.
  • Tool invoke (R21)ToolPlayground calls useInvokeTool with
    the two-call confirm-token protocol: first POST without a token,
    202 → TypeToConfirmModal (invoke-{toolName}), second POST with
    the server-minted token. ValidationError surfaces inline under
    the args form.
  • Audit replay (R21)AuditDrilldown Replay button uses the
    same two-call protocol on useReplayAudit.
  • Breaker reset (R21)BreakersPage reset uses a confirm-mode
    flip (simple Modal for first-leg, TypeToConfirmModal if the BE
    returns 202 with a minted token).
  • SSE live-feedApp.tsx retires the setInterval simulator
    in favour of subscribeEvents(). A livePausedRef lets the
    Pause/Resume toggle drop events WITHOUT reconnecting. Events are
    deduped by id (R25 spirit), buffer capped at 200.

Cross-cutting invariants

  • R14 — every mutation surfaces failures via toast; field-level
    ValidationError errors appear next to inputs.
  • R21 — destructive mutations strictly use the server-minted
    token from ConfirmTokenError.confirmTokenMint. Clients never
    invent tokens.
  • R11 / R29 — stable testids on every new action button + modal:
    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 5
    files: servers-mutations, tools-invoke, audit-replay,
    breakers-reset, dashboard-sse).
  • Bulk delete fan-out tested with happy + partial-failure paths.
  • Wizard 422 ValidationError verified to jump to step 1 + show
    inline error.
  • Wizard 401 verified to fire the global auth:expired event.
  • R21 two-call protocol exercised for invoke / replay / reset
    (token absent on first call, present on second).
  • SSE consumer: dedupe-by-id, pause-without-disconnect, unmount
    teardown.

CI expectation

Playwright fixture-drift between the SPA's wire expectations and
the real mcp-pack v1.4 endpoint shapes continues. That cleanup
is the W5 scope; page-level Vitest coverage locks in the R21 + R14
invariants in the meantime.

Excluded from this wave (carried to v1.2)

  • Settings page API-keys sub-section wiring — the
    useCreateApiKey / useRevokeApiKey hooks exist; UI wiring is
    small enough to land standalone.

🤖 Generated with Claude Code

…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>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 via Promise.allSettled and field-level ValidationError inline.
  • Implements R21 two-call confirm-token protocol for tool invoke (ToolPlayground), audit replay (AuditDrilldown) and breaker reset (BreakersPage) using ConfirmTokenError.confirmTokenMint and TypeToConfirmModal.
  • Replaces the setInterval live-feed simulator in App.tsx with a single subscribeEvents() subscription, using a livePausedRef so 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.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment on lines +320 to +326
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,
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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).
@lopadova
Copy link
Copy Markdown
Contributor Author

@copilot review

Copy link
Copy Markdown

Copilot AI commented May 18, 2026

@copilot review

Reviewed on top of commit d4fce77. No additional code changes were needed from this review ping; current branch behavior is unchanged. CI: the older failing Playwright run was on the previous SHA (2022280), while runs for d4fce77 are in progress.

@lopadova lopadova merged commit dd6f702 into main May 18, 2026
9 of 10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants