add-mcp-step.test.tsxfix(connections): stop the add-MCP and recorder OAuth flows failing silently
Review findings on the connections UI. All of them share a shape: the flow
finished, nothing reported an error, and the user was left with a connection
that does not do what they asked for.
B1 The mandatory description was dropped for any branded server. The row was
matched by raw string against the URL the user typed, but the probe echoes
the input while the callback stores the driver's own URL, which for Pylon
carries a trailing slash. The dialog then closed as though it had saved.
Matched on a normalized resource identifier now (the same rule the server
uses), against the URL frozen when the popup opened rather than the still
editable field, and a genuine miss is toasted instead of swallowed.
B2 A popup blocked by Safari or Firefox left isConnecting set, which disables
every control on the recorder credential form: the card was inert until a
page reload. Both blocked-popup paths now clear the flag, drop the pending
key and say what happened.
S3 Refocusing Cedar mid-flow deleted the pending record, so finishing the
sign-in afterwards did nothing. The MCP branch now refetches first and keeps
the record until the row actually reports connected.
S4 Whether a recorder uses MCP OAuth was re-derived at focus time from live
query state, which is undefined mid-refetch; an MCP recorder read as
non-MCP goes to Klavis and 422s. The decision is recorded in the pending
payload when the flow starts.
S5 A token connection saved from the Organization tab silently became a
personal one. addMcpConnection has no org variant, so those forms now say
so; the manual client-app path does have one and is routed to
credentialVault.upsertOrg when the scope says org.
S6 Picking a provider and then pasting a different URL left the old brand name
on the new server. A name this form derived is cleared with the verdict; one
the user typed is kept.
S8 The section's reconnect listener stood down for the whole dialog, though
only the add step ever competes for the message. Ownership now follows the
in-flight sign-in, reported by the step itself.
Also: one ScopeSelect instead of two hand-duplicated selectors whose non-admin
notes had already drifted; a non-admin who owns an org row is no longer told to
ask themselves; providerName reused instead of re-derived; a redundant
capabilities cast dropped; and the catalog comment no longer claims a new entry
needs no server change, which a null providerId disproves.
apps/mail's jest allowlist did not name modules/integrations. Added, with six
tests over the two OAuth completion paths; all six fail against the code before
this change.
Co-Authored-By: Claude Opus 5 (1M context) <<email>>Aug 30, 2026, 1:06 PM