From beb62feef14e41acf4ce9bb3edd1327e6922c512 Mon Sep 17 00:00:00 2001 From: OrcaWin Date: Tue, 27 Oct 2026 08:28:06 -0700 Subject: [PATCH] test: remove 25 low-value tests and redundant parity suite (#34443) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> --- config/reliability-gates.jsonc | 26 +- config/scripts/ci-shard-timings.json | 1 - .../wsl-browser-network-relay-launch.test.ts | 37 +- src/main/cli/wsl-managed-cli.test.ts | 24 -- src/main/codebuddy/hook-service.test.ts | 29 -- .../github-check-details-timeout.test.ts | 19 - .../runtime/gitlab-job-trace-client.test.ts | 114 ------ .../src/runtime/gitlab-owner-api.test.ts | 74 +--- .../src/runtime/remote-server-parity.test.ts | 371 ------------------ 9 files changed, 20 insertions(+), 675 deletions(-) delete mode 100644 src/renderer/src/runtime/remote-server-parity.test.ts diff --git a/config/reliability-gates.jsonc b/config/reliability-gates.jsonc index a10ada80ee9..3c8410318d2 100644 --- a/config/reliability-gates.jsonc +++ b/config/reliability-gates.jsonc @@ -6010,7 +6010,7 @@ "invariant": "Opening one HTML preview from a paired client renders the workspace document in exactly one client-local browser tab, located by that document and served over the orca-preview scheme. The client gains exactly that one browser workspace and it is the document one — blank where a URL page carries a URL, named by the document, with the chip naming the file — while the host gains no browser page at all, neither in its own page registry nor in the tab snapshot its clients publish into. The preview occupies its own split without taking focus from the source editor; an explicit click activates it, and closing it removes only the preview. Following a document from a file link is the other half of that switch and does move the reader to it, tab group included, whether the preview is new or already open, because opening a file is a request to look at it. A document tab quit with the client comes back as the same row on a grant the relaunched client mints afresh. A preview is named by the browser page it is open in, not by a namespace of its own, and the page registry has two halves: a workspace-document guest is registered in its own map and is absent from the browsing one entirely. That absence is the fence. Page, session and profile management, agent tab enumeration and command targeting, download routing and certificate attribution all read the browsing map directly, in more places than a per-channel guard could be remembered in, so none of them can name a document page and none of them carries a guard. Browser tools the reader drives (element grab, hover describe, selection capture, the annotation viewport bridge) are the one operation that legitimately spans the halves, and they go through the single authority that reads both, keyed by the page and its hosting renderer. The halves are disjoint in both directions: browsing registration refuses a page the document half already holds, and minting a grant refuses a page the browsing half already holds, so one id can never name a surface in both. The headless backend acts on that refusal by destroying the window it had already opened rather than leaving a policy-less page behind an id nothing can drive, keeping nothing under that id for its own shutdown to hand back. Registration refuses on the same terms when the guest it was asked about is already gone. The exit door is guarded in both its halves: a preview withdraws by revoking its grant and never through the unregister channel, so a page the document half holds arriving there is refused before either the registration teardown or the grab-state disposal beside it, which would otherwise drop the intent an in-flight preview grab compares by identity and leave that grab answering ok without ever arming its guest. A bridge request whose guest does not resolve is refused without tearing down the page it named, so a misaddressed request cannot cancel a healthy page's in-flight downloads and grabs. The annotation viewport bridge resolves its guest when its serialized op actually runs rather than when the request arrived, so a cross-process navigation while it waited cannot leave the bridge installed in a retired guest while the reader looks at a new one. State main keys by a preview's page is disposed when that page's grant is revoked, which is the only signal a preview's surface is gone. A tool asking for a page whose guest has not attached yet waits for that registration and arms when it arrives, rather than answering not-ready at the reader; that wait resolves only the request already naming this page, never the worktree-wide or any-tab waits the CLI and agents use to ask for a browser tab to drive. Handing the previewed document to the reader's own machine routes on the owners its grant was minted against — the file's own connection owner and the worktree's own runtime owner, neither read from the tab's stored fields. Only a document proven to live on this machine reaches the client OS; one with a resolved remote owner is downloaded first; and one whose owner cannot be resolved at all, workspace root included, is refused with a message naming that, because the download route would otherwise read the same absolute path on the client and hand back a same-named local file under the remote document's name. A runtime-owned path that falls outside its worktree root is refused by that route itself and surfaces as a failure toast rather than a download. Nothing the document does writes a file to this machine either: the preview partition denies downloads outright instead of routing them through the browser download flow, which has no page to attribute a preview's bytes to and would otherwise reserve a name in this desktop's Downloads folder and write them there unprompted. That refusal is visible to the reader and invisible to the document: the preview's shell carries a fixed sentence saying downloads are off, published at most once per preview per interval so a document asking in a loop cannot fill Orca's chrome, while the page itself gets back exactly what it got before, which is nothing. The sentence names no file, because the document chooses the name it offers; and a refusal never takes the document away the way an entry document's own failure does, whatever it names. A preview is a browser tab, not an editor tab in a preview mode: it is named the way a browser tab is named — by the document it shows when that document declares a title, and by the file it shows when it does not — while the chip goes on naming the file and the host whatever the document calls itself. A title is refused on the same terms the url is: a document that declares none has Chromium report the grant URL as its title, and that title is stored, mirrored onto the tab and written to disk, so anything carrying the scheme falls back to the file instead. It is created by the preview action as a page located by its document, it carries the workspace-relative path copy the editor's path header owned, and closing it revokes the grant that made the document readable while a URL tab closing beside it revokes nothing. Chrome persisted by builds that made previews editor tabs is dropped on restore rather than coming back naming a surface no restore can produce, and the ordinary editor tab for the same document is left alone. A document tab is held back at the mobile publish boundary — no client holds its grant, and the wire has no tab kind for it — while an ordinary browser tab beside it still publishes. It is held back from the group projection that publishes tab order, recency and group activity as well as from the tab list itself, so no published group names a tab the phone is never sent. A browser page can be located by a workspace document instead of a URL, and the document is the whole of its stored identity. The grant and the orca-preview URL that document is served over are minted when the page mounts and replaced by a hard reload, so neither is ever written to the page's url, mirrored onto its tab, persisted or published: such a page's url is the blank URL from creation through restore, including when a session written elsewhere carries a grant URL in, and what the session carries is the worktree and path a restored page mints afresh against today's owners. Every door onto a page's url holds that line — creation, the title update, and the navigation commit alike — so a report about a document page cannot give it a URL it never had, and the title fallback and the loading affordance follow the url each door actually wrote. The mirror carries the document too, so a tab entry cannot go on naming a document its active page has left. Every guest in the app is policy-attached through one door: a workspace document takes a restricted profile there rather than a separate installer beside it, so the attachment bookkeeping that door owns — what registration refuses, and what teardown frees — covers a preview on the same terms as a browsing page, and a preview takes none of the browsing machinery that door installs. That authority answers from the moment the embedder hands the guest over rather than only after a later navigation: the guest binds to the grant it is already showing, so the tools reach the document the reader opened and not just one they navigated to. A read the host reports as truncated or over-cap is refused rather than served partially, and a document outside the paired worktree is refused with a message naming that boundary instead of a bare read failure. The rendered document reaches nothing off-machine on its own: every served response carries a self-only content security policy, the preview session cancels any request that is not in-document, subframes cannot navigate outside the grant, a guest no document has yet bound to a grant may not navigate at all, the guest gathers no ICE candidates, and an SSH path that canonicalizes outside the grant root is refused before it is read. The one route out is a link the reader presses: a trusted click on an anchor, reported by the preview's own preload from a guest still bound to a live grant, leaves through the configured browser destination and captured source route — and only after the reader confirms the exact destination URL, so a document cannot spend a single stray press exfiltrating what it can read into a link it authored. The preview hands its guest that focus itself whenever it is the surface the reader is in — a browsing page gets it from the chrome around it, and a preview has no chrome to get it from — and it does so only then, so a preview mounted behind a terminal or an editor never takes the keyboard from what the reader is actually in. It offers again when the window itself takes focus back and nothing in the embedder has claimed that focus, because another app coming to the front lands focus on the embedder rather than the guest and the route out would otherwise stay shut until something remounted the pane — while the same window focus also arrives when the reader presses a tab, that being the guest's own blur returning, and taking focus back from there would fight the reader for their own click. Nothing else does. A navigation or popup the document starts by itself is swallowed whatever else is happening, including immediately after a genuine press elsewhere in the document, so a page that can read its grant cannot hand it to a browser tab; a middle click opens nothing; and a fragment link is answered inside the document. A preview attach carries the preview preload and no renderer-supplied one, and no other attach path can acquire it. A subresource the workspace will not send degrades the document to a notice naming that file, never to a failure panel over a page that rendered. A grant outlives neither the tab that owns it nor the renderer document that minted it, and only the trusted renderer can mint or revoke one. For the browser creations this gate still owns, owner-pinned creation returns the canonical host page identity before navigation readiness; delayed navigation cannot turn a created page into an unidentifiable failure or a duplicate retry. Capability rejection before host mutation must preserve the original error, issue no RPC, surface a failure toast, and remove only a caller-declared newly-created empty split. Post-create reconciliation failure requires exact rollback; ambiguous rollback rejects without local fallback.", "oracle": "In paired Electron, write an HTML fixture that declares its own title on the host, invoke the Explorer preview action on the client, and require the document text to be readable out of the orca-preview guest before judging any absence. With that presence established, require the client to hold exactly one browser workspace more than its baseline and that workspace to be the document one: page and tab url blank, the document path mirrored onto both, the tab named by the document's title, the chip naming the file, no editor row of the retired preview species anywhere, and the guest URL carrying the orca-preview scheme. Ask the host through its own page registry as well as through the tab snapshot, and in the same run open an ordinary URL browser tab from the same client and require that one to arrive in both — the presence precondition without which “the host gained nothing” is satisfied just as well by an oracle that cannot see browser pages at all. Require the preview to sit in a group other than the source editor's while the active group and tab remain the source editor's. Then click away to the terminal, click the preview tab, require it to reactivate and still render, close it with its own X, and require the document tab to be gone while the host still holds only the URL tab and the source group, source editor and terminal survive. Quit the client with a document tab open and relaunch it on the same profile: require the same workspace row to come back, blank and named by the document, rendering the document again over a grant URL that differs from the one that was quit, with no preview-scheme or document-named page anywhere in what the host holds. Prove the halves are live by flipping one product property at a time and requiring the run to fail: publish document workspaces to the host like ordinary ones, and stop mirroring the document onto the workspace row. Have the fixture document attempt its own egress on every load — an unattended window.open and location.href to an off-machine URL, plus an inline ICE gathering probe — and require the same baseline counts and a candidate count of zero, so the document's own attempts are measured rather than assumed. Then, as a separate phase after the close oracle has already run, bring the client window to the front, press the document's heading with a real mouse event, and require the document to report that the same press drove it to attempt a second window.open and location.href while both browser counts stay at that phase's baseline and nothing routes — the case a recent-input gate cannot distinguish from the press's own effect. Only then press the target=_blank link with a real mouse event and require both a recorded routing call that returned success and a browser count above that baseline, with the preview tab still open. Drive the preload's click policy as a unit oracle over a real document: a dispatched click, a trusted press on an external anchor, an anchor reached through what it wraps, an SVG animated href, a sibling preview link, fragment and percent-encoded fragment targets, a bare hash, and a middle click. Create a browser page located by a workspace document, handing creation a live grant URL, and require its stored url, its mirrored tab url and the written session payload all to be blank with no orca-preview string anywhere in what was written, while an ordinary page created the same way keeps the URL it was given and asks for the address bar the document page never does. Parse the written page and tab through the session schema and require the document to survive both halves. Hydrate them back and require the document page to return blank and still named — including when its page row was salvaged away and only the tab's own copy remains, and when a foreign session carried a grant URL into both rows. Drive the mirror across a page switch out of the document and back, and across a repair in which the document is the only mirrored field that differs. Name a document page from its document and require the tab to take that name, name it with an empty title and require the file, name it with a live grant URL and require the file again with no preview scheme anywhere in the written session, and require an ordinary blank browser tab beside it to still be called New Tab. Dispatch a title update out of a rendered preview's own guest and require it to reach the page state while the identity chip still reads the document's workspace-relative path. Attach a browsing guest and a workspace-document guest through the same method in one run and require the browsing one to take clicked-link routing, popup handling and auth-identity detach tracking while the document guest takes none of them, stays inside the grant it is showing, denies every window it asks for, and is dropped from the page-keyed document registry by the same teardown that frees its id for a later attach. Register a browsing guest and attach a workspace-document guest in one run against the real manager, require the one door to answer each page with the guest of its own half, and require the document page to be absent from the browsing map and from its enumeration. Drive both browsing registration entry points with a page the document half already holds and require them to register nothing, and drive the mint channel with a page the browsing half already holds and require it to refuse; and drive the offscreen one with a guest that is missing and with one already destroyed, requiring the same refusal. Arm a grab on a live preview target, drive the unregister channel at that same target in the window before the queued operation runs, and require the grab to reach the guest anyway — then drive the same sequence for an ordinary browser page and require its grab state to be disposed after all. Hold one viewport-bridge op open, queue a second behind it, swap the page's guest while that second op waits, and require the injection to land in the guest the page has then. Revoke a grant after a tool has run against its page and require that page's grab state to be cancelled and disposed. Ask a tool for a document page whose guest has not attached, require the request to park in the registration wait, attach the guest, and require the same request to arm on it; require a page nothing ever renders to answer not-ready once that wait elapses. With a document open, ask a tool for a browsing page id and require it to be answered by the browsing half or not at all, with the same channel reaching the document guest under the page it really renders. Drive open-externally for a document whose per-file owner is remote while the workspace-scoped owner is unresolved, for a runtime-owned worktree whose preview tab carries no runtime id of its own, and for a worktree that resolves no runtime owner while the tab still carries one, requiring the download route in each; and for an owner that cannot be resolved at all, and for an unknown workspace root while nothing names another host, requiring a refusal that neither opens nor downloads. Drive the headless backend with a page the document half already holds and require it to reject, destroy the window, and unregister nothing — then shut the backend down and require it still to have unregistered nothing. Navigate a bound preview guest at a second grant through both latch events and require it to stay on the grant it bound to. Mount a preview while a renderer drag is already in flight and require its guest to be click-through at the moment it is appended, not a turn later. Render the editor panel shell in each remaining tab mode and require the path header exactly where the surface does not already name itself. Drive the preview action and require a browser tab located by the document rather than an editor tab, require a second open of the same document to activate the tab it is already in, and require closing that tab to revoke its grant while a URL tab closed beside it revokes none. Hydrate a session carrying preview chrome from a build that made previews editor tabs and require it dropped while the ordinary editor tab for the same document survives. Publish a worktree holding a document tab and a URL tab and require only the URL tab to reach the mobile snapshot. Install the shared partition policies for a preview partition and for an ordinary browsing partition in the same run, fire each one's own will-download listener, and require the preview's to cancel while the browsing one still reaches the download router — then require the preview protocol installer to be what asks for that deny. In the same run, require the cancelled download to raise a reader-facing notice and the routed one to raise none. Drive that notice directly for a guest bound to a live grant, for repeated attempts inside and outside its interval, for two previews at once, and for a contents no preview is bound to; require the guest registry to name the bound grant for a live preview guest and nothing for a contents that is not one, has committed no document, or is gone. Drive the shell with a refusal and require one fixed sentence, still one row after three more refusals, standing beside an asset failure rather than being counted with it, gone behind the failure panel, and ignored when it names another preview's grant. Drive the main-side report gate directly for a sender that is no preview guest, a guest with no bound or a revoked grant, a genuine press Electron's webview focus flag misreports as unfocused, and non-web URLs; drive the reader-facing confirmation for accept, cancel, and a confirmed tab the browser refuses; and drive will-attach-webview in both preload directions. Run the per-owner reader, grant-containment, scheme-admission, guest-policy, and plan-routing contracts as unit oracles, including a host-reported truncation, an over-cap binary, and an out-of-worktree paired path. Drive the reader-facing component with the payloads the reader can actually produce — the entry document fails only as truncated or unreadable, a subresource additionally as a refused format — and require the asset case to leave the guest mounted. Drive the closed-tab cleanup hook, the window installer, and the grant IPC handlers directly, requiring the grant to be released when the preview tab closes, cleared at window creation and on a cross-document main-frame navigation, and refused to any sender that is not the trusted renderer. For the browser creations this gate still owns, run the unchanged contract oracle for direct create and side-preview callers with absent status, unknown capabilities, and a mixed-version host, requiring the original unsupported error or visible toast, zero RPCs, and no retained new split; hold a real navigation response beyond the 15-second client deadline after host creation and require the first RPC to return the exact host inventory page ID, one host page, and no retry; repeat reconciliation faults against headless serve and retain the separate exact-page reconciliation rollback oracle.", "commands": [ - "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/orca-runtime-browser.test.ts src/main/runtime/rpc/methods/browser.test.ts src/renderer/src/lib/file-preview.test.ts src/renderer/src/runtime/web-session-browser-placement.test.ts src/renderer/src/runtime/web-runtime-session.test.ts src/renderer/src/runtime/web-session-tabs-sync.test.ts src/renderer/src/runtime/remote-server-parity.test.ts", + "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/orca-runtime-browser.test.ts src/main/runtime/rpc/methods/browser.test.ts src/renderer/src/lib/file-preview.test.ts src/renderer/src/runtime/web-session-browser-placement.test.ts src/renderer/src/runtime/web-runtime-session.test.ts src/renderer/src/runtime/web-session-tabs-sync.test.ts src/renderer/src/runtime/web-session-tabs-sync-focus-intent.test.ts src/renderer/src/runtime/web-session-tabs-sync-browser-tabs.test.ts src/renderer/src/runtime/web-session-tabs-sync-client-owned-placement.test.ts src/renderer/src/runtime/web-session-tabs-sync-layout-groups.test.ts", "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/runtime/web-runtime-browser-materialization.test.ts", "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/runtime/web-runtime-browser-capability-cleanup.test.ts", "pnpm exec vitest run --config config/vitest.config.ts src/main/browser/doc-preview-grant-registry.test.ts src/main/browser/doc-preview-file-reader.test.ts src/main/browser/doc-preview-protocol.test.ts src/main/browser/doc-preview-guest-policy.test.ts src/main/browser/doc-preview-failure-notice.test.ts src/shared/doc-preview-scheme.test.ts src/renderer/src/lib/doc-preview-grants.test.ts src/renderer/src/lib/file-preview.test.ts src/main/window/main-window-webview-security.test.ts src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.failure-message.test.tsx src/renderer/src/components/browser-pane/workspace-doc/doc-preview-external-link-confirmation.test.ts src/renderer/src/components/terminal-pane/terminal-file-link-actions.test.ts", @@ -6052,7 +6052,6 @@ "src/renderer/src/runtime/web-runtime-browser-capability-cleanup.test.ts", "src/renderer/src/runtime/web-runtime-session.test.ts", "src/renderer/src/runtime/web-session-tabs-sync.test.ts", - "src/renderer/src/runtime/remote-server-parity.test.ts", "src/renderer/src/hooks/useIpcEvents-browser-tab-create.test.ts", "src/renderer/src/hooks/useIpcEvents-close-routing-browser-pages.test.ts", "src/renderer/src/hooks/useIpcEvents-close-routing-session-tabs.test.ts", @@ -6095,7 +6094,11 @@ "tests/e2e/paired-remote-html-preview-local-render.spec.ts", "tests/e2e/paired-preview-address-bar-convergence.spec.ts", "tests/e2e/paired-browser-create-navigation-deadline.spec.ts", - "tests/e2e/paired-browser-creation-reconciliation-failure.spec.ts" + "tests/e2e/paired-browser-creation-reconciliation-failure.spec.ts", + "src/renderer/src/runtime/web-session-tabs-sync-focus-intent.test.ts", + "src/renderer/src/runtime/web-session-tabs-sync-browser-tabs.test.ts", + "src/renderer/src/runtime/web-session-tabs-sync-client-owned-placement.test.ts", + "src/renderer/src/runtime/web-session-tabs-sync-layout-groups.test.ts" ], "assertionRefs": [ { @@ -6181,7 +6184,7 @@ ] }, { - "file": "src/renderer/src/runtime/remote-server-parity.test.ts", + "file": "src/renderer/src/runtime/web-session-tabs-sync-browser-tabs.test.ts", "assertions": [ "a caller-created browser gains focus when the exact predecessor tab is still visible" ] @@ -6698,7 +6701,8 @@ "command": "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/orca-runtime-browser.test.ts src/main/runtime/rpc/methods/browser.test.ts src/renderer/src/lib/file-preview.test.ts src/renderer/src/runtime/web-session-browser-placement.test.ts src/renderer/src/runtime/web-runtime-session.test.ts src/renderer/src/runtime/web-session-tabs-sync.test.ts src/renderer/src/runtime/remote-server-parity.test.ts", "result": "passed", "durationSeconds": 3.48, - "summary": "Seven focused host and renderer contract files passed 183/183 tests, covering owning-runtime routing, focused and unfocused creation, placement, reconciliation, failure cleanup, and teardown." + "summary": "Seven focused host and renderer contract files passed 183/183 tests, covering owning-runtime routing, focused and unfocused creation, placement, reconciliation, failure cleanup, and teardown.", + "currentCommand": "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/orca-runtime-browser.test.ts src/main/runtime/rpc/methods/browser.test.ts src/renderer/src/lib/file-preview.test.ts src/renderer/src/runtime/web-session-browser-placement.test.ts src/renderer/src/runtime/web-runtime-session.test.ts src/renderer/src/runtime/web-session-tabs-sync.test.ts src/renderer/src/runtime/web-session-tabs-sync-focus-intent.test.ts src/renderer/src/runtime/web-session-tabs-sync-browser-tabs.test.ts src/renderer/src/runtime/web-session-tabs-sync-client-owned-placement.test.ts src/renderer/src/runtime/web-session-tabs-sync-layout-groups.test.ts" }, { "date": "2026-08-13", @@ -10486,7 +10490,7 @@ "invariant": "For every claim-capable execution route, one provider-session identity has at most one live PTY owner and one canonical host surface across concurrent clients, retries, reconnects, and stale publications. For paired structured fresh and resume requests, the authenticated owning runtime creates in background without a renderer window; activate=true focuses the exact requested leaf only on the requesting viewer, while activate=false changes no viewer focus. A live orphan may be adopted only when the controller proves its exact handle and incarnation, its worktree and host owner match, no competing visual owner exists, and a host topology CAS wins. A viewer may classify completion only from successful host/provider inspection or explicit lifecycle evidence; transport, handle, or provider unavailability remains unknown and breaks any consecutive-idle proof. A physical exit retires that exact incarnation durably so stale client state and host restart cannot recreate it. Mixed-version routes select the unchanged legacy request before any authority side effect or execution-owner-local filesystem access.", "oracle": "Race independent clients and repeated operation IDs, then assert one physical spawn and one canonical PTY/surface; inject exit-before-reply, provider disconnect, conflicting claim scope, old daemon/relay capabilities, reused handles, stale incarnations, owner mismatch, and topology revision conflict; assert safe adoption or explicit failure without a second spawn or wrong-process attachment. Run fresh/resume with activate true/false against an isolated headed desktop host and a separate paired client, then against isolated headless serve: assert host presentation stays background, only the requesting viewer focuses the exact leaf, inactive calls preserve client/DOM focus, a same-version publication replay cannot lose focus intent, and sibling-first split publication cannot consume exact-leaf intent. Restore legacy split panes and groups beside a newer host-owned tab, preserving exact predecessor/new/successor order, output, input, resize, titles, tab/leaf identity, active group, and multi-client convergence. For completion, drive a known running agent through outer transport loss, authoritative provider rejection, reconnect, explicit stop, real exit status, and successful hook completion; assert unavailable evidence never dispatches completion and two fresh authoritative idle samples are required after the gap. After exact exit, assert terminal and tab listings omit the surface, a stale publication cannot restore it, restart cannot resurrect it, exact tokened fixture PIDs are dead, and unrelated tabs/processes survive until scoped cleanup.", "commands": [ - "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/rpc/methods/agent-session.test.ts src/renderer/src/runtime/web-runtime-session.test.ts src/renderer/src/runtime/web-session-tabs-sync.test.ts src/renderer/src/runtime/web-session-intent-owner.test.ts src/renderer/src/runtime/remote-server-parity.test.ts", + "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/rpc/methods/agent-session.test.ts src/renderer/src/runtime/web-runtime-session.test.ts src/renderer/src/runtime/web-session-tabs-sync.test.ts src/renderer/src/runtime/web-session-intent-owner.test.ts src/renderer/src/runtime/web-session-tabs-sync-focus-intent.test.ts src/renderer/src/runtime/web-session-tabs-sync-browser-tabs.test.ts src/renderer/src/runtime/web-session-tabs-sync-client-owned-placement.test.ts src/renderer/src/runtime/web-session-tabs-sync-layout-groups.test.ts", "pnpm exec vitest run --config config/vitest.config.ts src/shared/claimed-agent-pty-owner.test.ts src/main/daemon/daemon-pty-adapter.test.ts src/main/runtime/orca-runtime-agent-session-operation.test.ts src/main/runtime/remote-agent-session-host-authority.integration.test.ts src/main/runtime/orca-runtime-terminal-retirement.test.ts src/renderer/src/components/terminal-pane/remote-runtime-pty-transport-host-session-launch.test.ts src/renderer/src/components/terminal-pane/remote-runtime-pty-transport-create-handoff.test.ts src/renderer/src/runtime/remote-runtime-session-tabs-inflight.test.ts src/renderer/src/runtime/web-runtime-session.test.ts src/renderer/src/runtime/web-session-tabs-sync.test.ts", "pnpm exec vitest run --config config/vitest.config.ts tests/e2e/remote-terminal-tab-retirement.unit.test.ts", "pnpm test:repro:remote-agent-session", @@ -10524,7 +10528,6 @@ "src/renderer/src/runtime/web-runtime-session.test.ts", "src/renderer/src/runtime/web-session-tabs-sync.test.ts", "src/renderer/src/runtime/web-session-intent-owner.test.ts", - "src/renderer/src/runtime/remote-server-parity.test.ts", "tests/e2e/remote-agent-session-focus-authority.spec.ts", "config/scripts/remote-agent-session-authority-repro.mjs", "config/scripts/remote-agent-session-process-cleanup.mjs", @@ -10533,7 +10536,11 @@ "src/main/runtime/terminal-orphan-owner.test.ts", "src/main/runtime/terminal-orphan-topology.test.ts", "src/renderer/src/runtime/web-session-terminal-orphan-recovery.test.ts", - "src/renderer/src/runtime/web-session-terminal-orphan-mixed-version.test.ts" + "src/renderer/src/runtime/web-session-terminal-orphan-mixed-version.test.ts", + "src/renderer/src/runtime/web-session-tabs-sync-focus-intent.test.ts", + "src/renderer/src/runtime/web-session-tabs-sync-browser-tabs.test.ts", + "src/renderer/src/runtime/web-session-tabs-sync-client-owned-placement.test.ts", + "src/renderer/src/runtime/web-session-tabs-sync-layout-groups.test.ts" ], "assertionRefs": [ { @@ -10708,7 +10715,8 @@ "command": "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/rpc/methods/agent-session.test.ts src/renderer/src/runtime/web-runtime-session.test.ts src/renderer/src/runtime/web-session-tabs-sync.test.ts src/renderer/src/runtime/web-session-intent-owner.test.ts src/renderer/src/runtime/remote-server-parity.test.ts", "result": "passed", "durationSeconds": 2.28, - "summary": "Five focused files and 140 tests passed on the structural candidate, covering authenticated host presentation normalization, trusted local preservation, fresh/resume viewer intent, same-version response/publication replay, exact split-leaf focus, sibling-first publication, and paired-runtime parity." + "summary": "Five focused files and 140 tests passed on the structural candidate, covering authenticated host presentation normalization, trusted local preservation, fresh/resume viewer intent, same-version response/publication replay, exact split-leaf focus, sibling-first publication, and paired-runtime parity.", + "currentCommand": "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/rpc/methods/agent-session.test.ts src/renderer/src/runtime/web-runtime-session.test.ts src/renderer/src/runtime/web-session-tabs-sync.test.ts src/renderer/src/runtime/web-session-intent-owner.test.ts src/renderer/src/runtime/web-session-tabs-sync-focus-intent.test.ts src/renderer/src/runtime/web-session-tabs-sync-browser-tabs.test.ts src/renderer/src/runtime/web-session-tabs-sync-client-owned-placement.test.ts src/renderer/src/runtime/web-session-tabs-sync-layout-groups.test.ts" }, { "date": "2026-07-23", diff --git a/config/scripts/ci-shard-timings.json b/config/scripts/ci-shard-timings.json index 02099ce9256..5852b2a95c3 100644 --- a/config/scripts/ci-shard-timings.json +++ b/config/scripts/ci-shard-timings.json @@ -11205,7 +11205,6 @@ "src/renderer/src/runtime/remote-runtime-terminal-stale-stream-frames.test.ts": 173, "src/renderer/src/runtime/remote-runtime-terminal-stall-recovery.test.ts": 702, "src/renderer/src/runtime/remote-server-install-failure-probe.test.ts": 28, - "src/renderer/src/runtime/remote-server-parity.test.ts": 1246, "src/renderer/src/runtime/remote-server-restart-wait.test.ts": 72, "src/renderer/src/runtime/remote-server-update-coordinator.test.ts": 163, "src/renderer/src/runtime/remote-terminal-layout-resolution.test.ts": 39, diff --git a/src/main/browser/wsl-browser-network-relay-launch.test.ts b/src/main/browser/wsl-browser-network-relay-launch.test.ts index b0e23846a4d..97f4bd828f4 100644 --- a/src/main/browser/wsl-browser-network-relay-launch.test.ts +++ b/src/main/browser/wsl-browser-network-relay-launch.test.ts @@ -1,14 +1,9 @@ import { execFileSync } from 'node:child_process' -import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs' +import { mkdtempSync, readFileSync, rmSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' import { afterEach, describe, expect, it, vi } from 'vitest' -import { orcadPosixNodeRuntimeGlobs } from '../managed-server/install/orcad-node-runtime-globs' -import { - buildWslBrowserNetworkGuestInstallScript, - buildWslBrowserNetworkGuestLaunchScript, - resolveWslBrowserNetworkRelayBundle -} from './wsl-browser-network-relay-launch' +import { buildWslBrowserNetworkGuestInstallScript } from './wsl-browser-network-relay-launch' const roots: string[] = [] @@ -20,34 +15,6 @@ afterEach(() => { }) describe('WSL browser network relay launch', () => { - it('builds a shell-valid exact-version launcher with a Node 18 floor', () => { - const script = buildWslBrowserNetworkGuestLaunchScript('0.1.0+abc123') - - execFileSync('sh', ['-n'], { input: script }) - expect(script).toContain('.orca-wsl/browser-network/0.1.0+abc123') - expect(script).toContain('Number(process.versions.node.split(".")[0])>=18') - expect(script).toContain('wsl-browser-network-relay.js') - expect(() => buildWslBrowserNetworkGuestLaunchScript("bad'version")).toThrow( - 'browser_tunnel_execution_host_unavailable' - ) - }) - - it('falls back to orcad pinned runtimes after system node, under a launcher-stamped version', () => { - const forLine = buildWslBrowserNetworkGuestLaunchScript('0.1.0+abc') - .split('\n') - .find((line) => line.startsWith('for c in ')) - const [orcadRuntime, orcadMachineRuntimes] = orcadPosixNodeRuntimeGlobs() - expect(forLine).toContain(`"$HOME/.local/bin/node" ${orcadRuntime} ${orcadMachineRuntimes}; do`) - - const relayRoot = mkdtempSync(join(tmpdir(), 'orca-wsl-browser-network-bundle-')) - roots.push(relayRoot) - vi.stubEnv('ORCA_RELAY_PATH', relayRoot) - mkdirSync(join(relayRoot, 'wsl')) - writeFileSync(join(relayRoot, 'wsl', 'wsl-browser-network-relay.js'), '') - writeFileSync(join(relayRoot, 'wsl', '.browser-network-version'), '0.1.0+abc\n') - expect(resolveWslBrowserNetworkRelayBundle()?.version).toMatch(/^0\.1\.0\+abc\.[0-9a-f]{8}$/) - }) - it('installs exact bundle bytes and writes the version marker last', () => { const root = mkdtempSync(join(tmpdir(), 'orca-wsl-browser-network-')) roots.push(root) diff --git a/src/main/cli/wsl-managed-cli.test.ts b/src/main/cli/wsl-managed-cli.test.ts index 23e764f5a5b..a7b2a856e51 100644 --- a/src/main/cli/wsl-managed-cli.test.ts +++ b/src/main/cli/wsl-managed-cli.test.ts @@ -2,7 +2,6 @@ import { mkdtempSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } import { tmpdir } from 'node:os' import { join } from 'node:path' import { afterEach, describe, expect, it } from 'vitest' -import { installFakeAppEnvironment } from '../../../config/scripts/vitest-host-ports-setup' import { getManagedWslCliDir } from './wsl-managed-cli' const roots: string[] = [] @@ -37,32 +36,9 @@ describe('managed WSL CLI provisioning', () => { expect(getManagedWslCliDir({ ...update, userDataPath: host.userDataPath })).not.toBe(directory) }) - it('provides nothing when the packaged CLI runtime is missing', () => { - const host = fixture() - rmSync(join(host.resourcesPath, 'bin', 'orca.exe')) - expect(getManagedWslCliDir(host)).toBeNull() - }) - it('provides nothing when user data cannot hold the CLI', () => { const host = fixture() writeFileSync(host.userDataPath, 'a file, not a directory') expect(getManagedWslCliDir(host)).toBeNull() }) - - it('runs the development CLI directly with the dev launcher env', () => { - const host = fixture() - const appPath = host.resourcesPath - const cliEntryPath = join(appPath, 'out', 'cli', 'index.js') - mkdirSync(join(appPath, 'out', 'cli'), { recursive: true }) - writeFileSync(cliEntryPath, 'fixture') - installFakeAppEnvironment({ getPath: () => host.userDataPath, getAppPath: () => appPath }) - const directory = getManagedWslCliDir({ ...host, isPackaged: false }) ?? '' - expect(readFileSync(join(directory, 'orca-dev'), 'utf8')).toContain(process.execPath) - const bridge = readFileSync(join(directory, 'orca-wsl-bridge.ps1'), 'utf8') - expect(bridge.startsWith('\uFEFF')).toBe(true) - expect(bridge).toContain(host.userDataPath) - expect(bridge).toContain(cliEntryPath) - expect(bridge).toContain('$env:ORCA_APP_EXECUTABLE_NEEDS_APP_ROOT') - expect(bridge).toContain('Remove-Item Env:NODE_OPTIONS') - }) }) diff --git a/src/main/codebuddy/hook-service.test.ts b/src/main/codebuddy/hook-service.test.ts index cca83aa9903..54c99319d87 100644 --- a/src/main/codebuddy/hook-service.test.ts +++ b/src/main/codebuddy/hook-service.test.ts @@ -18,35 +18,6 @@ beforeAll(() => { }) afterAll(() => rmSync(sandbox.home, { recursive: true, force: true })) -describe('CodeBuddy managed hooks', () => { - it('preserves user configuration through repeated install and removal', () => { - const path = join(sandbox.home, '.codebuddy', 'settings.json') - const userHook = { hooks: [{ type: 'command', command: 'echo user-hook' }] } - const settings = { - model: 'custom', - hooks: { Stop: [userHook] }, - statusLine: { command: 'user-status' } - } - writeFileSync(path, JSON.stringify(settings)) - expect(codebuddyHookService.install().state).toBe('installed') - expect(codebuddyHookService.install().state).toBe('installed') - const installed = JSON.parse(readFileSync(path, 'utf8')) - for (const event of CODEBUDDY_HOOK_EVENTS) { - expect(installed.hooks[event]).toHaveLength(event === 'Stop' ? 2 : 1) - } - expect(installed.statusLine).toEqual(settings.statusLine) - expect(codebuddyHookService.remove().state).toBe('not_installed') - expect(JSON.parse(readFileSync(path, 'utf8'))).toMatchObject(settings) - }) - - it('leaves malformed user settings untouched', () => { - const path = join(sandbox.home, '.codebuddy', 'settings.json') - writeFileSync(path, '{broken') - expect(codebuddyHookService.install().state).toBe('error') - expect(readFileSync(path, 'utf8')).toBe('{broken') - }) -}) - describe('CodeBuddy managed hooks on Windows', () => { const platform = Object.getOwnPropertyDescriptor(process, 'platform')! afterEach(() => Object.defineProperty(process, 'platform', platform)) diff --git a/src/renderer/src/runtime/github-check-details-timeout.test.ts b/src/renderer/src/runtime/github-check-details-timeout.test.ts index a06c27d7012..13bb833a958 100644 --- a/src/renderer/src/runtime/github-check-details-timeout.test.ts +++ b/src/renderer/src/runtime/github-check-details-timeout.test.ts @@ -39,19 +39,6 @@ describe('withGitHubCheckDetailsTimeout', () => { expect(operationSignal?.aborted).toBe(true) }) - it('arms the renderer deadline before starting the operation', async () => { - let timerCountWhenStarted = 0 - - const result = withGitHubCheckDetailsTimeout(async () => { - timerCountWhenStarted = vi.getTimerCount() - return 'details' - }) - - await expect(result).resolves.toBe('details') - expect(timerCountWhenStarted).toBe(1) - expect(vi.getTimerCount()).toBe(0) - }) - it('keeps the timeout error when abort-aware work rejects synchronously', async () => { const stalled = withGitHubCheckDetailsTimeout( (signal) => @@ -76,10 +63,4 @@ describe('withGitHubCheckDetailsTimeout', () => { withGitHubCheckDetailsTimeout(() => Promise.reject(new Error(message))) ).rejects.toMatchObject({ message: 'Localized timeout.' }) }) - - it('preserves unrelated operation failures', async () => { - await expect( - withGitHubCheckDetailsTimeout(() => Promise.reject(new Error('authentication failed'))) - ).rejects.toThrow('authentication failed') - }) }) diff --git a/src/renderer/src/runtime/gitlab-job-trace-client.test.ts b/src/renderer/src/runtime/gitlab-job-trace-client.test.ts index cb81a7d37e1..9a7c85eaec9 100644 --- a/src/renderer/src/runtime/gitlab-job-trace-client.test.ts +++ b/src/renderer/src/runtime/gitlab-job-trace-client.test.ts @@ -25,58 +25,6 @@ beforeEach(() => { }) describe('loadGitLabJobLogDetails', () => { - it('returns null for a check that is not a GitLab job, touching no transport', async () => { - const githubCheck: PRCheckDetail = { - name: 'verify', - status: 'completed', - conclusion: 'failure', - url: 'https://github.com/acme/orca/runs/1', - checkRunId: 7 - } - - await expect( - loadGitLabJobLogDetails({ repoPath: '/repo', check: githubCheck }) - ).resolves.toBeNull() - expect(jobTrace).not.toHaveBeenCalled() - expect(callRuntimeRpc).not.toHaveBeenCalled() - }) - - it('asks main for a bounded excerpt over local IPC', async () => { - jobTrace.mockResolvedValue({ ok: true, trace: 'ERROR: Job failed: exit code 1' }) - - const details = await loadGitLabJobLogDetails({ - repoPath: '/repo', - repoId: 'repo-1', - check: gitLabCheck - }) - - expect(jobTrace).toHaveBeenCalledWith({ - repoPath: '/repo', - repoId: 'repo-1', - jobId: 42, - projectRef: null, - logExcerpt: true - }) - expect(details?.jobs[0]?.logTail).toContain('ERROR: Job failed: exit code 1') - }) - - it('targets the MR project so a fork pipeline trace is not looked up in the wrong project', async () => { - jobTrace.mockResolvedValue({ ok: true, trace: 'boom' }) - - await loadGitLabJobLogDetails({ - repoPath: '/repo', - repoId: 'repo-1', - check: gitLabCheck, - projectRef: { host: 'gitlab.example.test', path: 'contributor/orca' } - }) - - expect(jobTrace).toHaveBeenCalledWith( - expect.objectContaining({ - projectRef: { host: 'gitlab.example.test', path: 'contributor/orca' } - }) - ) - }) - it('does not request a trace for a manual job that cannot have one', async () => { const manualCheck: PRCheckDetail = { name: 'deploy: production', @@ -98,57 +46,6 @@ describe('loadGitLabJobLogDetails', () => { expect(details?.summary).toBe('No log is available for this GitLab job.') }) - // Canceled-before-start jobs are completed/cancelled; fetch and show main’s empty trace without error (#7732). - it('explains an empty trace for a job canceled before it produced output', async () => { - jobTrace.mockResolvedValue({ ok: true, trace: '' }) - const canceledCheck: PRCheckDetail = { - name: 'unit', - status: 'completed', - conclusion: 'cancelled', - url: null, - gitlabJobId: 5 - } - - const details = await loadGitLabJobLogDetails({ - repoPath: '/repo', - check: canceledCheck - }) - - expect(details?.jobs).toEqual([]) - expect(details?.summary).toBe('No log is available for this GitLab job.') - }) - - it('routes to the owning runtime environment and still requests the excerpt', async () => { - callRuntimeRpc.mockResolvedValue({ ok: true, trace: 'remote failure' }) - - await loadGitLabJobLogDetails({ - repoPath: '/repo', - repoId: 'repo-1', - repoOwnerExecutionHostId: 'runtime:env-9', - check: gitLabCheck - }) - - expect(jobTrace).not.toHaveBeenCalled() - expect(callRuntimeRpc).toHaveBeenCalledWith( - { kind: 'environment', environmentId: 'env-9' }, - 'gitlab.jobTrace', - // Why: bounding in main keeps the response under the 1 MB transport frame cap. - expect.objectContaining({ repo: 'id:repo-1', jobId: 42, projectRef: null, logExcerpt: true }), - { timeoutMs: 65_000 } - ) - }) - - it('surfaces the GitLab error verbatim so the panel does not claim "no details"', async () => { - jobTrace.mockResolvedValue({ ok: false, error: '403 Forbidden' }) - - await expect( - loadGitLabJobLogDetails({ - repoPath: '/repo', - check: gitLabCheck - }) - ).rejects.toThrow('403 Forbidden') - }) - it('gives up on a local IPC call that never settles, matching the remote timeout', async () => { vi.useFakeTimers() try { @@ -165,15 +62,4 @@ describe('loadGitLabJobLogDetails', () => { vi.useRealTimers() } }) - - it('falls back to a translated message when GitLab reports a blank error', async () => { - jobTrace.mockResolvedValue({ ok: false, error: ' ' }) - - await expect( - loadGitLabJobLogDetails({ - repoPath: '/repo', - check: gitLabCheck - }) - ).rejects.toThrow('Failed to load the GitLab job log.') - }) }) diff --git a/src/renderer/src/runtime/gitlab-owner-api.test.ts b/src/renderer/src/runtime/gitlab-owner-api.test.ts index e5166f53186..6c9fb98a6e8 100644 --- a/src/renderer/src/runtime/gitlab-owner-api.test.ts +++ b/src/renderer/src/runtime/gitlab-owner-api.test.ts @@ -8,7 +8,7 @@ vi.mock('./runtime-rpc-client', () => ({ })) import { gitLabApiFor } from './gitlab-owner-api' -import { forgeCredentialTarget, forgeOwnerHostIdForWorkspace } from './forge-credential-target' +import { forgeCredentialTarget } from './forge-credential-target' const glListIssues = vi.fn() @@ -20,46 +20,6 @@ beforeEach(() => { }) describe('gitLabApiFor', () => { - it('reads a server-owned repo on that server', async () => { - const selector = { - repoPath: '/work/app', - repoId: 'server-repo', - repoOwnerExecutionHostId: 'runtime:owner-server' - } - await gitLabApiFor(selector).listIssues({ ...selector, state: 'opened' }) - - expect(glListIssues).not.toHaveBeenCalled() - expect(rpc.call).toHaveBeenCalledWith( - { kind: 'environment', environmentId: 'owner-server' }, - 'gitlab.listIssues', - expect.objectContaining({ repo: 'id:server-repo', state: 'opened' }), - { timeoutMs: 30_000 } - ) - }) - - it("loads a server-owned repo's reviewers from that server", async () => { - const reviewer = { - id: 7, - username: 'ana', - name: 'Ana', - avatarUrl: 'https://gitlab.example.com/ana.png' - } - rpc.call.mockResolvedValue([reviewer]) - const selector = { - repoPath: '/work/app', - repoId: 'server-repo', - repoOwnerExecutionHostId: 'runtime:owner-server' - } - - await expect(gitLabApiFor(selector).listAssignableUsers(selector)).resolves.toEqual([reviewer]) - expect(rpc.call).toHaveBeenCalledWith( - { kind: 'environment', environmentId: 'owner-server' }, - 'gitlab.listAssignableUsers', - expect.objectContaining({ repo: 'id:server-repo' }), - { timeoutMs: 30_000 } - ) - }) - it('offers no reviewers from a server older than the reviewer RPC', async () => { rpc.call.mockRejectedValue( Object.assign(new Error('Unknown method'), { code: 'method_not_found' }) @@ -86,17 +46,6 @@ describe('gitLabApiFor', () => { ) }) - it.each(['ssh:devbox', 'local'])( - 'uses this computer for a %s repo', - async (repoOwnerExecutionHostId) => { - const selector = { repoPath: '/work/app', repoId: 'repo', repoOwnerExecutionHostId } - await gitLabApiFor(selector).listIssues(selector) - - expect(rpc.call).not.toHaveBeenCalled() - expect(glListIssues).toHaveBeenCalledOnce() - } - ) - it('lets a task source name the host and the server-side repo id', async () => { const selector = { repoPath: '/work/app', @@ -133,25 +82,4 @@ describe('gitLabApiFor', () => { expect(rpc.call).not.toHaveBeenCalled() expect(glListIssues).not.toHaveBeenCalled() }) - - it('sends an SSH workspace behind a server to that server, a direct SSH one to this computer', async () => { - const repo = { executionHostId: 'runtime:owner-server' as const } - const nested = forgeOwnerHostIdForWorkspace(repo, { - hostId: 'ssh:devbox', - runtimeOwnerEnvironmentId: 'owner-server' - }) - const selector = { repoPath: '/work/app', repoId: 'repo', repoOwnerExecutionHostId: nested } - await gitLabApiFor(selector).listIssues(selector) - - expect(rpc.call).toHaveBeenCalledWith( - { kind: 'environment', environmentId: 'owner-server' }, - 'gitlab.listIssues', - expect.anything(), - expect.anything() - ) - expect(forgeOwnerHostIdForWorkspace({ connectionId: 'devbox' }, { hostId: 'ssh:devbox' })).toBe( - 'ssh:devbox' - ) - expect(forgeOwnerHostIdForWorkspace({ connectionId: 'devbox' }, null)).toBe('ssh:devbox') - }) }) diff --git a/src/renderer/src/runtime/remote-server-parity.test.ts b/src/renderer/src/runtime/remote-server-parity.test.ts deleted file mode 100644 index c96e561bfbc..00000000000 --- a/src/renderer/src/runtime/remote-server-parity.test.ts +++ /dev/null @@ -1,371 +0,0 @@ -// Exercise deterministic server-authoritative reconcile against local tab ordering/focus/disconnect semantics (remote-server-parity-test-plan.md). Live checklist covers geometry, sidebar, screencast, mobile and two-host UI flows. -import { beforeEach, describe, expect, it } from 'vitest' -import type { RuntimeMobileSessionTabsResult } from '../../../shared/runtime-types' -import { toWebTerminalSurfaceTabId } from '../../../shared/terminal-surface-id' -import type { Tab } from '../../../shared/tab-types' -import { - applyFreshWebSessionTabsSnapshot, - applyWebSessionTabsSnapshot -} from './web-session-tabs-sync/snapshot-api' -import { resetWebSessionTabsSnapshotFreshnessForTests } from './web-session-tabs-sync/tracking-lifecycle' -import type { WebSessionTabsSyncState } from './web-session-tabs-sync/state' -import { - recordWebSessionFocusIntent, - resetWebSessionFocusIntentForTests -} from './web-session-focus-intent' - -const WT = 'repo::/worktree' -const ENV = 'web-env-1' -const NOW = 1_700_000_000_000 -const LEAF_A = '11111111-1111-4111-8111-111111111111' -const LEAF_B = '22222222-2222-4222-8222-222222222222' -const LEAF_C = '33333333-3333-4333-8333-333333333333' - -function makeState(overrides: Partial = {}): WebSessionTabsSyncState { - return { - activeBrowserTabId: null, - activeBrowserTabIdByWorktree: {}, - activeFileId: null, - activeFileIdByWorktree: {}, - activeGroupIdByWorktree: {}, - activeTabId: null, - activeTabIdByWorktree: {}, - activeTabType: 'terminal', - activeTabTypeByWorktree: {}, - activeWorktreeId: WT, - agentStatusByPaneKey: {}, - agentStatusEpoch: 0, - browserCertificateFailuresByPageId: {}, - browserPagesByWorkspace: {}, - browserTabsByWorktree: {}, - groupsByWorktree: {}, - layoutByWorktree: {}, - openFiles: [], - editorBuffers: {}, - ptyIdsByTabId: {}, - remoteBrowserPageHandlesByPageId: {}, - tabBarOrderByWorktree: {}, - tabsByWorktree: {}, - terminalLayoutsByTabId: {}, - unifiedTabsByWorktree: {}, - unreadTerminalTabs: {}, - sortEpoch: 0, - ...overrides - } -} - -type HostTerminal = { parentTab: string; leaf: string; active: boolean; title?: string } - -function terminalSnapshotTab(t: HostTerminal): RuntimeMobileSessionTabsResult['tabs'][number] { - return { - type: 'terminal', - id: `${t.parentTab}::${t.leaf}`, - title: t.title ?? t.parentTab, - parentTabId: t.parentTab, - leafId: t.leaf, - isActive: t.active, - status: 'ready', - terminal: `${t.parentTab}-pty` - } -} - -function makeSnapshot( - terminals: HostTerminal[], - overrides: Partial = {} -): RuntimeMobileSessionTabsResult { - const tabs = terminals.map(terminalSnapshotTab) - const active = terminals.find((t) => t.active) - return { - worktree: WT, - publicationEpoch: `epoch-${overrides.snapshotVersion ?? 1}`, - snapshotVersion: 1, - activeGroupId: 'host-group-1', - activeTabId: active ? `${active.parentTab}::${active.leaf}` : null, - activeTabType: active ? 'terminal' : null, - tabGroups: [ - { - id: 'host-group-1', - activeTabId: active?.parentTab ?? null, - tabOrder: terminals.map((t) => t.parentTab) - } - ], - tabs, - ...overrides - } -} - -// Seed realistic prior terminal/unified-tab/group state for snapshot reconciliation. -function localTerminal(parentTab: string, sortOrder: number, active: boolean) { - const id = toWebTerminalSurfaceTabId(parentTab) - const unified: Tab = { - id, - entityId: id, - groupId: 'host-group-1', - worktreeId: WT, - contentType: 'terminal', - label: parentTab, - customLabel: null, - color: null, - sortOrder, - createdAt: NOW + sortOrder, - isPreview: false, - isPinned: false - } - return { - id, - parentTab, - active, - storeTab: { - id, - ptyId: `remote:${ENV}@@${parentTab}-pty`, - worktreeId: WT, - title: parentTab, - customTitle: null, - color: null, - sortOrder, - createdAt: NOW + sortOrder - }, - unified - } -} - -function stateWithLocalTerminals( - locals: ReturnType[] -): WebSessionTabsSyncState { - const active = locals.find((l) => l.active) ?? locals[0] - return makeState({ - activeTabId: active?.id ?? null, - activeTabIdByWorktree: active ? { [WT]: active.id } : {}, - activeTabType: 'terminal', - activeTabTypeByWorktree: { [WT]: 'terminal' }, - tabsByWorktree: { [WT]: locals.map((l) => l.storeTab) }, - unifiedTabsByWorktree: { [WT]: locals.map((l) => l.unified) }, - tabBarOrderByWorktree: { [WT]: locals.map((l) => l.id) }, - groupsByWorktree: { - [WT]: [ - { - id: 'host-group-1', - worktreeId: WT, - activeTabId: active?.id ?? null, - tabOrder: locals.map((l) => l.id), - recentTabIds: locals.map((l) => l.id) - } - ] - } - }) -} - -function groupOrder(patch: Partial): string[] { - return patch.groupsByWorktree?.[WT]?.[0]?.tabOrder ?? [] -} -function groupActive(patch: Partial): string | null { - return patch.groupsByWorktree?.[WT]?.[0]?.activeTabId ?? null -} - -beforeEach(() => { - resetWebSessionTabsSnapshotFreshnessForTests() - resetWebSessionFocusIntentForTests() -}) - -describe('parity §3: remote terminal create appends rightmost (matches local)', () => { - it('a newly created remote terminal is ordered last, after existing tabs', () => { - const prior = stateWithLocalTerminals([ - localTerminal('host-tab-1', 0, true), - localTerminal('host-tab-2', 1, false) - ]) - recordWebSessionFocusIntent({ environmentId: ENV }, WT, `host-tab-3::${LEAF_C}`) - const patch = applyWebSessionTabsSnapshot( - prior, - makeSnapshot([ - { parentTab: 'host-tab-1', leaf: LEAF_A, active: false }, - { parentTab: 'host-tab-2', leaf: LEAF_B, active: false }, - { parentTab: 'host-tab-3', leaf: LEAF_C, active: true } - ]), - ENV, - NOW + 10 - ) as Partial - - const order = groupOrder(patch) - // Local rule: new tab appends to the end. The new one must be last. - expect(order.at(-1)).toBe(toWebTerminalSurfaceTabId('host-tab-3')) - expect(order).toEqual([ - toWebTerminalSurfaceTabId('host-tab-1'), - toWebTerminalSurfaceTabId('host-tab-2'), - toWebTerminalSurfaceTabId('host-tab-3') - ]) - }) -}) - -describe('parity §4: remote create focuses new tab; echoes never steal focus', () => { - it('a client-initiated create focuses the new terminal (intent honored)', () => { - const prior = stateWithLocalTerminals([localTerminal('host-tab-1', 0, true)]) - recordWebSessionFocusIntent({ environmentId: ENV }, WT, `host-tab-2::${LEAF_B}`) - const patch = applyWebSessionTabsSnapshot( - prior, - makeSnapshot([ - { parentTab: 'host-tab-1', leaf: LEAF_A, active: false }, - { parentTab: 'host-tab-2', leaf: LEAF_B, active: true } - ]), - ENV, - NOW + 10 - ) as Partial - expect(patch.activeTabIdByWorktree?.[WT]).toBe(toWebTerminalSurfaceTabId('host-tab-2')) - expect(groupActive(patch)).toBe(toWebTerminalSurfaceTabId('host-tab-2')) - }) - - it('an unsolicited status echo (no intent) does NOT steal focus from current', () => { - const prior = stateWithLocalTerminals([ - localTerminal('host-tab-1', 0, false), - localTerminal('host-tab-2', 1, true) - ]) - // No focus intent recorded — this is an agent "thinking" echo marking tab-1 active. - const patch = applyWebSessionTabsSnapshot( - prior, - makeSnapshot([ - { parentTab: 'host-tab-1', leaf: LEAF_A, active: true }, - { parentTab: 'host-tab-2', leaf: LEAF_B, active: false } - ]), - ENV, - NOW + 10 - ) as Partial - // Status echoes cannot steal focus; client-owned placement leaves groups unchanged. - const effectiveGroups = patch.groupsByWorktree?.[WT] ?? prior.groupsByWorktree[WT] - expect(effectiveGroups?.[0]?.activeTabId).toBe(toWebTerminalSurfaceTabId('host-tab-2')) - }) -}) - -describe('parity §2: snapshot freshness (no split-brain from stale updates)', () => { - it('ignores a stale lower-version snapshot after a newer version applied', () => { - const prior = stateWithLocalTerminals([localTerminal('host-tab-1', 0, true)]) - const newer = makeSnapshot([{ parentTab: 'host-tab-1', leaf: LEAF_A, active: true }], { - snapshotVersion: 3, - publicationEpoch: 'epoch-x' - }) - const older = makeSnapshot([{ parentTab: 'host-tab-1', leaf: LEAF_A, active: true }], { - snapshotVersion: 2, - publicationEpoch: 'epoch-x' - }) - const first = applyFreshWebSessionTabsSnapshot(prior, newer, ENV, NOW + 10) - const afterNewer = { ...prior, ...(first as Partial) } - const second = applyFreshWebSessionTabsSnapshot(afterNewer, older, ENV, NOW + 20) - expect(second).toBe(afterNewer) - }) -}) - -describe('parity §11: remote browser create focuses the new browser tab', () => { - it('honors focus intent for a newly created browser session tab', () => { - const pageId = 'browser-page-1' - const prior = stateWithLocalTerminals([localTerminal('host-tab-1', 0, true)]) - recordWebSessionFocusIntent( - { environmentId: ENV }, - WT, - pageId, - undefined, - toWebTerminalSurfaceTabId('host-tab-1') - ) - const patch = applyWebSessionTabsSnapshot( - prior, - makeSnapshot([{ parentTab: 'host-tab-1', leaf: LEAF_A, active: false }], { - activeTabId: pageId, - activeTabType: 'browser', - tabGroups: [ - { - id: 'host-group-1', - activeTabId: pageId, - tabOrder: ['host-tab-1', pageId] - } - ], - tabs: [ - terminalSnapshotTab({ parentTab: 'host-tab-1', leaf: LEAF_A, active: false }), - { - type: 'browser', - id: pageId, - title: 'example.com', - browserWorkspaceId: pageId, - browserPageId: pageId, - url: 'https://example.com', - loading: false, - canGoBack: false, - canGoForward: false, - isActive: true - } - ] - }), - ENV, - NOW + 10 - ) as Partial - expect(patch.activeTabTypeByWorktree?.[WT]).toBe('browser') - expect(patch.activeBrowserTabIdByWorktree?.[WT]).toBe(pageId) - }) - - it('a browser status echo without intent does not steal focus from a terminal', () => { - const pageId = 'browser-page-1' - const prior = makeState({ - activeTabId: toWebTerminalSurfaceTabId('host-tab-1'), - activeTabIdByWorktree: { [WT]: toWebTerminalSurfaceTabId('host-tab-1') }, - activeTabType: 'terminal', - activeTabTypeByWorktree: { [WT]: 'terminal' }, - tabsByWorktree: { [WT]: [localTerminal('host-tab-1', 0, true).storeTab] }, - unifiedTabsByWorktree: { [WT]: [localTerminal('host-tab-1', 0, true).unified] }, - tabBarOrderByWorktree: { [WT]: [toWebTerminalSurfaceTabId('host-tab-1')] }, - groupsByWorktree: { - [WT]: [ - { - id: 'host-group-1', - worktreeId: WT, - activeTabId: toWebTerminalSurfaceTabId('host-tab-1'), - tabOrder: [toWebTerminalSurfaceTabId('host-tab-1')], - recentTabIds: [toWebTerminalSurfaceTabId('host-tab-1')] - } - ] - }, - browserTabsByWorktree: { - [WT]: [ - { - id: pageId, - worktreeId: WT, - activePageId: pageId, - pageIds: [pageId], - url: 'https://example.com', - title: 'example.com', - loading: false, - faviconUrl: null, - canGoBack: false, - canGoForward: false, - loadError: null, - createdAt: NOW - } - ] - } - }) - // No intent — server snapshot marks the (pre-existing) browser active. - const patch = applyWebSessionTabsSnapshot( - prior, - makeSnapshot([{ parentTab: 'host-tab-1', leaf: LEAF_A, active: false }], { - activeTabId: pageId, - activeTabType: 'browser', - tabGroups: [{ id: 'host-group-1', activeTabId: pageId, tabOrder: ['host-tab-1', pageId] }], - tabs: [ - terminalSnapshotTab({ parentTab: 'host-tab-1', leaf: LEAF_A, active: false }), - { - type: 'browser', - id: pageId, - title: 'example.com', - browserWorkspaceId: pageId, - browserPageId: pageId, - url: 'https://example.com', - loading: false, - canGoBack: false, - canGoForward: false, - isActive: true - } - ] - }), - ENV, - NOW + 10 - ) as Partial - // Unchanged reconcile fields may be absent; visible type must remain terminal, never browser. - const nextType = patch.activeTabTypeByWorktree?.[WT] ?? 'terminal' - expect(nextType).toBe('terminal') - }) -})