Repository navigation
fix(web): Unlink this PC clears a T3 Connect link from any state - #177
Conversation
A PC linked under one T3 Connect account could not be unlinked once both switches showed OFF, or once another account was signed in. The only path to the unlink call ran when a switch that showed ON was turned OFF. Every attempt to link then failed with the different-account conflict. Settings > Connections now shows an Unlink this PC row whenever a link is stored. It calls the local unlink and needs no relay token and no sign-in to the account that made the link. The relay:write scope is still needed. The conflict error names the row, and the row says when the stored link belongs to another account than the one signed in.
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
Review - standards and specTwo independent read-only reviews of d14e674. Verdict: no blocking finding. Security checks hold: no file under Owed in a follow-up pull request, not blocking this one:
Not acted on, by standing fork decisions: the wording "Unlink this PC" was asked for by name; evidence images on a Full reports follow. Spec review - PR 177The core fix meets the spec, with one gap: the root cause of the stuck state is not found or fixed. Confirmed by reading the code:
(a) Missing or partial
(b) Not asked for
(c) Implemented but questionable
Double click, failed unlink, toggle race and stale error all behave correctly. Next action: decide whether finding 1 blocks the merge. Standards review - PR 177No high-severity breach. Four documented-standard findings and six baseline smells. Documented standards
Baseline smellsAll judgement calls.
Checked and clean
|
Problem
A PC whose server holds a T3 Connect link made under one account could not be unlinked after signing in as another account. Every attempt to switch T3 Connect on failed with "This environment is already linked to a different cloud account. Unlink it before switching accounts." No click reached the unlink call.
The only route to
environment.cloud.unlinkwasreconcileCloudStatewhen neither a managed tunnel nor publishing is wanted. That runs only when a switch that shows ON is turned OFF. A stored link with no tunnel and publishing off shows both switches OFF. Turning either one ON links as the signed-in account and hits the conflict.Upstream has not fixed this.
upstream/main(2cf0ff0643) has the same single route inuseCloudLinkController.ts, so there was no upstream shape to follow.Fix
This PC is already linked to a different T3 Connect account. Use "Unlink this PC" in Settings > Connections, then try again.cloudUserIddiffers from the signed-in Clerk user id, the row says the PC is linked to a different account. The relay setscloudUserIdfrom the token subject, which is the Clerk user id. When either id is unknown the row shows the plain description.validateLinkedCloudUseris untouched and unlink still needs therelay:writescope. Without that scope the button is disabled with the same permission tooltip the switches use.The logic lives in two fork files,
forkUnlinkThisPc.tsandForkUnlinkThisPcRow.tsx. The two upstream files gain 13 and 14 lines.fork-features.jsonhas a newt3-connect-unlink-this-pcentry with the keep rule.docs/user/remote-access.mdgains one paragraph.Reproduction
Throwaway dev server on an empty home under
%TEMP%/fm-unlink-control, made-up Clerk key and relay URL, no sign-in. The link was made through the real endpoint with a made-up account id:States that could not reach unlink on
main:On
mainthe page in that state has no unlink control:Real run with the fix
Same server, same stuck state. The headless browser clicked Unlink:
The link attempt as a second account gets past the conflict check after the unlink. In the page the switches stay disabled because nobody is signed in, which is the user's step.
Plain web (no desktop bridge), same state:
Limits of this run:
window.desktopBridgeexists. The run did not launch the built desktop app. The script set a stand-inwindow.desktopBridgein the headless page after boot: every member is a function, subscriptions return an unsubscribe function,getLocalEnvironmentBearerTokenreturns the throwaway server's own dev token, and every other call never settles. No product code changed for this. The plain web screenshot uses no stand-in.Tests
apps/web/src/cloud/forkUnlinkThisPc.test.tsxmountsuseCloudLinkControllerwith the commands mocked, the same shape as upstream'suseCloudLinkController.test.tsx. It covers: unlink from the stuck state withclerkToken: nulland no token read, unlink while signed out, relay revoke when the same account is signed in, local unlink when the token read fails, a failed unlink, the conflict error naming the control, the error clearing after unlink, and other errors left unchanged.Fails on
main: I removed the two new source files and restoredmain'suseCloudLinkController.tsandConnectionsSettings.tsx, leaving only the test file, then ran it:The one that passes on
mainchecks that other link errors keep their wording.With the fix:
Checks
The fork features check exits 1 on this Windows machine because of the 11
scripts/build-desktop-artifact.test.tsfailures. They fail the same way onmain(fddd2c2):Every other fork feature test passes, including the new one.
Surfaces
ConfiguredCloudLinkRow, which all three places that render the T3 Connect rows share. The first-run Connect dialog uses the same controller and gets the reworded conflict error.docs/user/remote-access.md.