* feat(ssh): offer a Node.js mirror when neither machine can download Node
* fix(ssh): put the mirror action beside Details on the host row
* fix(ssh): offer the mirror only where this computer's setting applies, and word main's error by mirror state
* test(ssh): type the refusal case
* test(ssh): one checked settings fixture for the mirror dialog
* fix(orcad): ship node-pty's winpty backend so Windows 1809 hosts can open terminals
node-pty selects winpty below Windows build 18309, but the Windows server
slot carried only the ConPTY addon, so the candidate's PTY self-test failed
on Windows 10 1809 / Server 2019 and the host was recorded as unsupported.
Reported by @lksr202 in #30906.
* test(orcad): smoke the winpty backend in the Windows prebuild slot
* fix(projects): a moved SSH host's hidden setups stay hidden, so its hosts list once (#30859)
Reported by @matheusrenov.
* fix(projects): hide a moved folder-only host's setup placeholders too
* test(projects): cover a WSL-moved setup; read the move journal once
* test(projects): type the setup catalog stubs instead of casting
A freshly restarted cell can be ready while the global load balancer still
answers 503 for it. The probe retried once after 2 s, so c10's 2026-10-20
roll failed after its drain and was left isolated. Retry wrapped source
5xx every 10 s for up to 2 minutes.
Co-authored-by: E2E Test <e2e@test.local>
* fix(editor): markdown preview reads its file with the source tab's grant and host
A preview of a terminal-opened file outside every workspace on a managed
server dropped the source tab's one-file read grant, so the editor refused
the read as an external local file. A client-local file in an SSH workspace
lost its readOnly flag the same way and was read from the SSH host instead.
Reported-by: @quzard
Fixes#31034
* fix(editor): a retargeted preview keeps its read authority after the source closes
* fix(editor): reload an open preview when its source gets a fresh grant
* Send a status batch's generated tab titles to main as one rename (dark, layout-owner build only)
* Share the window's as-today refusal rule with the title batch; cover a failed batch and a paused workspace
* Move the renameTabs request schema to its own module, under the file's line limit
---------
Co-authored-by: E2E Test <e2e@test.local>
* fix(updater): a live orcad's browser helper pauses for macOS desktop installs
orcad starts its browser helper from the installed Orca.app, so ShipIt waits
for it, and the installer refused it as an unregistered blocker with no
supported way out. orcad now registers the helper in the existing serve
install park: it stops the helper for the install and starts it again from
the new bundle once the hold ends. The refusal card for a helper an older
orcad still runs says what to do instead of "stop the server".
Reported-by: @routesmith
* fix(orcad): retry a failed helper restart, hold through a mid-swap bundle, catalog the guidance
* fix(orcad): a new park cancels a slow helper restart; reset backoff per install
* fix(relay): move director traffic in two steps so a deploy does not land on one instance
Cloud Run routes a new director revision's floor instances their first request
roughly 60-110 s after they start, while a traffic move reaches clients in
15-30 s. The one-step 100% move therefore put every assignment on the single
instance started with the revision, which sits at its own admission limit at
peak; the 2026-10-20 deploy returned ~550 assign 503s in two minutes that way.
With a floor above one, the deploy now moves 20% first, waits until Cloud Run's
request log shows every floor instance serving (six-minute deadline), then
moves the rest. A timeout or failure at that stage returns all traffic to the
previous serving revision, which still holds its warm floor. The staging deploy
identity gains log read access for the same check.
* fix(relay): bound the director spread log read, log the instances seen at timeout, and document split recovery
A hung gcloud log read could hold the 20/80 split past the six-minute deadline;
each read now times out after 30 s and counts as an unread poll. A timeout logs
the distinct instances seen, so a partial share packed onto fewer instances than
the floor shows up. The runbook covers restoring a split left by a cancelled job
and the missing selector-rollback tag after a timed-out deploy.
* fix(layout): main sweeps a stored terminal row the window would not reattach, so no empty extra tab shows (dark, layout-owner build only)
A stored terminal row with no tab-bar entry became a tab in main's layout even when nothing
would reattach it, so with main owning the layout the window showed an empty extra terminal tab
that today's build never shows. Today's window drops such a row at startup: it keeps one only
when its startup reconnect plan names a terminal for it (the row's own terminal in a workspace
live at shutdown and not on SSH, where that id is only a wake hint; an SSH relay session id; or a
split row's own pane), and removes the rest with their pane layouts.
With the switch on, main's Store load now applies that same sweep once, beside the existing
tab-level binding repair, so main's layout, frames and saves never hold the row. Sleeping agent
records stay, as they do in today's window. A selection naming a swept row moves as the window's
sweep moves it.
The window-parity tests now restore with today's window as the oracle and load as main does with
the switch on (its startup sweep, then the Loader), so they hold under either build; the ghost-tab
entry is removed and each kept and dropped shape has a profile.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(layout): the startup sweep keeps an SSH row whose own terminal the window may reattach (dark, layout-owner build only)
The window ignores an SSH row's own terminal id only when it finds the worktree listed; an SSH
folder workspace or an unlisted SSH worktree reattaches by that id. Main cannot see the listing
at load, so the sweep keeps such a row rather than risk deleting a terminal the window keeps.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(layout): the startup sweep keeps a row any partition's shutdown list names live (dark, layout-owner build only)
The window reads one shutdown list merged from every partition, so a stale list in one partition
can mark another's workspace live. The sweep now keeps a row live by its own partition's rule or
any partition's list, so it never drops a row the window keeps. A session from before the tab
bar is swept as the window sweeps it (parity profile added).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: E2E Test <e2e@test.local>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(relay): give region-correction reconnects and roll re-placements the in-region reserve fallback
Every desktop session open carries a region-correction request, and those
skipped the reserve plan entirely, so with the region's database cells full they
still spilled abroad while an in-region reserve cell had room. The plan now runs
for them in a mode that never answers itself (the database lane must reply so the
window exchange follows) and offers only the in-region reserve fallback.
A host re-placed off a roll-isolated cell went straight to the other-regions tier
when its own region's tier was full. With an in-region reserve fallback it now
books that first, and the roll canary event is emitted for the reserve booking.
* fix(relay): never pace a roll drain on reserve intake, and count every reserve move off an isolated cell
A host leaving a roll-isolated cell whose region was full could get a paced 503
from a throttled reserve cell, stretching the drain and re-running the failed
in-region transaction on each retry. For those hosts a pace is now no room, and
they spill as before. Sticky now says when it declined an isolated pin, so a
share-draw booking off that cell also emits the roll canary event.
Keep same-name projects short across execution hosts and show their machine beside host-owned headers, including when collapsed. Reuse existing host identities and filtered section membership; retain global ownership for shared projects.
Includes tooltip, narrow-sidebar, alias and filtering regression fixes with visual proof in the PR.
Co-authored-by: KAPUIST <thsxornjs12@gmail.com>
* fix(renderer): an editor file write and an unqualified removal route through the rows, never the Active Server focus
resolveWriteRouteResult is the focus-free owner route for writes that name no host. Removal (and
its mid-flight guard) and the editor's catalog-owner lookup use it; tests that relied on focus for
unstamped server rows now stamp them, as the client does when they land.
* fix(editor): retained-text owner keys use the same focus-free route as the file's writes
A corrupt or truncated .orca-web-client-files.json threw while the remote
server built its HTTP handler, which could stop the server from starting.
Catch it, warn, and answer browser requests with 404 instead.
Both sat 10-20 min in the shared ubuntu-latest queue on 10-19/20, leaving
reserve cells unwatched between segments. The rollout workflows already
run on this pool.
* fix(ssh): say the host dropped this desktop's pairing, not that another Orca holds the port
* fix(ssh): pair again over SSH when our own managed server refuses this desktop's token
* fix(ssh): key re-pairs by the refused revision, cap attempts, retry on explicit connect
* fix(ssh): keep a newer pairing stored mid-repair, count only completed reads, and offer Connect, not an access link, for managed servers
* fix(ssh): judge a re-pair only against the pairing still stored; Check connection retries a managed server's pairing
* fix(ssh): a pane whose managed server refuses this desktop says why and offers Reconnect, instead of spinning
* test(e2e): live failure path for a refused managed pairing
* fix(ssh): a Connect that re-paired answers from the new pairing, not the retired one
* fix(ssh): only an explicit Connect lifts a managed re-pair's hold and cap; say SSH access can pair again
Startup restore reaches ssh:connect with automatic: true and went through the same
ensureTunnel that cleared the hold, so repeated automatic reconnects could bypass the
three-attempt cap. The reset now lives in connectTarget's explicit branch.
The Shared Server Access footnote now says revoking there doesn't stop someone with
SSH access to this computer from pairing again.
* ci(e2e): route the managed pairing-repair spec with the managed-host remote sources
* fix(ssh): the repair gate decides whether a managed tunnel builds, not the build
A refused shared-control open rebuilt the tunnel (SSH execs, forward, handshake, wake)
before the held failure or the attempt cap was consulted, so reopens on a blocked
server rebuilt without limit. buildWithPairingRepair now asks the gate first: a failure
stands for the refused pairing revision for 15 s, or through the window once the cap is
spent, and every caller gets it without reaching the host.
- A connect during an in-flight repair keeps its reset (per-environment reset epoch).
- An unpaired answer fails at once; it is not a moved port, so no re-read or wake.
- A refusal that only rebuilt the tunnel no longer reports "pairing changed".
- WSL and cloud VMs no longer say Orca tried to pair over SSH, and Check connection
only re-pairs servers managed over SSH (runtimePairingRepairRoute).
- Translate the new strings; route the pane-banner files to the managed-SSH e2e lane.
* fix(ssh): fence a status re-pair follow-up to the same server, and hold a refused repair under its own revision
- getRuntimeEnvironmentStatus followed any pairing change mid-probe, past a caller's
expectedEnvironmentPairingRevision fence. It now follows only for an unpinned caller and only
a new pairing of the same SSH-managed server under its pinned host key.
- recordRefusedAfterRepair stood under whatever revision was stored now, so a newer pairing
stored mid-refusal was blocked untried; it stands under the repaired revision.
- The WSL restart test expects the refused-pairing classification main's WSL path now reaches.
* fix(ssh): a re-pair hands its callers the new credentials, and a failed one judges only the pairing it tried
- ensureOrcadManagedTunnel returns the environment as stored once the tunnel stands. The
terminal census and a deploy's already-current result use it, so after a re-pair they
no longer authenticate with the refused token, which read as an unverifiable census and
refused restarts, updates and stops.
- The shared-control refusal handler blocks the status owner only while the failure stands
for the pairing stored now (managedOrcadPairingFailureStands). A newer pairing stored
meanwhile keeps its owner and retries.
* fix(ssh): migrations commit with the pairing the tunnel stands on, and a Connect mid-handshake stays reset
- Conversion binds the environment ensureOrcadManagedTunnel returns, so the destination, the
server project reads and the result use the re-paired credentials (the migration mark is kept).
- A delta move gets its destination only from connectDestination, which opens the tunnel and
builds the destination from what it returns; a pre-ensure destination can no longer exist. A
tunnel that cannot open keeps the delta journaled and the host marked for the next move.
- buildWithPairingRepair takes the reset epoch when it starts, so a refusal after the re-pair
cannot reinstate a failure that a Connect pressed during the handshake cleared.
* refactor(ssh): one module owns a shared control socket's environment policy, keeping request-connections under its line limit
* feat(orcad-migration): unsaved drafts stay on this desktop and are renamed to the server on commit
* fix(orcad-migration): refuse clashing drafts from the rename's own collection; stricter live spec
* fix(orcad-migration): stamp renamed drafts with the server, rename at startup after a cut-off commit, keep draft refusals
* fix(orcad-migration): retain only after a startup rename is durable; startup survives an unreadable journal
* fix(orcad-migration): a cut-off commit is renamed and retained at startup, so the rename runs once
* fix(orcad-migration): one retain per migration at a time; no rollback that could drop newer edits
* test(e2e): check the visible draft in whichever editor a large file opens in
* fix(orcad-migration): startup retains only migrations of hosts this profile owns
* ci(e2e): route the editor-drafts migration spec to the sources it covers
* Main routes a floating terminal or removed project without reading every project (dark, layout-owner build only)
In a layout-owner build, finding a worktree's save partition checked for a
project registered on two machines by listing every project on every call,
including ids that cannot belong to a project. Skip that list for ids with no
registered project, and reuse the list a hydration pass already read.
* A dragged-out pane with no shell yet opens its new tab in the pane's folder (dark, layout-owner build only)
In a layout-owner build, main builds the dragged-out pane's new tab and the
window shows main's tab, so the window's folder for the pane never reached it
and the new shell started in the source tab's folder. The window now sends the
pane's folder with the move as an optional field, and main uses it when the
moved pane has no terminal yet. An older main drops the field and keeps today's
folder.
* A chat cancelled while it is being created stays closed when the late reply arrives (dark, layout-owner build only)
In a layout-owner build, cancelling a new chat on this computer closes it on
the host without writing a cancellation record, and the host still answers
the in-flight create as successful. That answer then rebuilt the closed chat's
conversation reader, which nothing would ever close. The cancel now notes the
closed chat in memory, and the create answer skips the reader for it. No
message between the window and the host changes.
---------
Co-authored-by: E2E Test <e2e@test.local>
* Show short Antigravity pool labels in the status bar
Antigravity pools rendered their full "<group> · <agy window name>" in the
status bar. The host now publishes structured group/windowName fields on each
bucket, and the renderer labels pools as short group + window length
("Gemini 5h", "Claude/GPT wk"), with a reset countdown once a pool is urgent.
Old hosts without the fields keep today's full names; the click panel and
tooltips are unchanged.
Co-Authored-By: Claude <noreply@anthropic.com>
* Keep Antigravity status bar reset countdowns current
* Preserve rate-limit pool identities in status labels
---------
Co-authored-by: Claude <noreply@anthropic.com>
* fix(sidebar): a pin's reveal and a native drag's source lane follow the card's own host
Pinning a same-id twin no longer scrolls and flashes the focused card, and the reveal names the
focused copy's host. A native drag reads its source lane from the card's own row instead of the
first lane holding the id.
* fix(sidebar): the lineage reveal walks the focused copy's host; drop the inert native-drag change
* fix(sidebar): a server-proxied focused row still follows its pin, revealed by its own host
* fix(relay): keep a host in its region when the database lane is full and a reserve cell has room
A host that lost the reserve share draw went to the database lane, which
spills to another region when its own region's database cells are full,
even while an in-region reserve cell had free seats. The database lane now
requires the region when an in-region reserve cell has room; if the region
is full it books that reserve cell, and only spills when neither has room.
* fix(relay): pace a throttled in-region reserve cell instead of spilling, and decide reserve room at plan time
With the region's database cells full, a reserve cell with seats but no intake
budget fell through the placer's database-cells shortcut and the host went
abroad. That placement now answers pace (503 with Retry-After). regionReserve
is a single callback, present only while an in-region reserve cell has a seat.
* fix(relay): pace only on a reserve cell that lacked budget, not one that refused
A cell that refused this placement (full, unreachable, seated-newer) got its
token back and drove a 1 s Retry-After forever while the map still showed a
seat. Pacing now skips cells refused for anything but intake, so those
placements fall to the database lane's cross-region fallback as before.
* fix(provider-process): kill a provider group its SIGKILLed supervisor leaves behind
* fix(provider-process): re-read a provider start in its read second; poll instead of sleeping in tests
* fix(provider-process): keep the report channel through the Codex session adapter; re-prove same-second starts
* fix(provider-process): never kill a leaderless provider group; list guard files in the CLI project
* fix(layout): restored terminals named only on their tab reattach after a restart (dark, layout-owner build only)
In a layout-owner build, a terminal recorded only on its tab (an older session, or an SSH tab
whose relay session was never visited) started a new shell after a restart and orphaned the old
one, and an unvisited SSH tab lost its relay session id on the next save.
- Main's Loader binds a one-pane tab's own terminal to its unbound pane in a workspace that was
live at shutdown, as the window's reconnect does, so main's frames and saves hold it.
- The window's reconnect writes the restored row terminal again: ptyId is a field the frame merge
leaves to the window, so main's frames never set it on a restored row.
* fix(layout): main binds a restored tab's own terminal once at load, not on every Loader run (dark, layout-owner build only)
The Loader re-derived the binding on each load from fields the window rewrites live, so an exit
main recorded could be undone. A switch-gated Store load repair now binds a one-pane tab's own
terminal to its unbound pane, as the window's reconnect does, and main's saves keep it. It skips
a terminal another mounted pane or a tab-bar tab holds, and a paired server's partition.
* fix(layout): an SSH workspace's restored tab binds only its relay session id; repair runs after the load purge (dark, layout-owner build only)
* test(layout): the reconnect gate test expects the row ptyId write; cover the repair's purge order and SSH repo predicate
---------
Co-authored-by: E2E Test <e2e@test.local>
Report the execution host's accepted, launching, started, skipped, failed, or completed status and print the available run/workspace/terminal identities. Add safe same-target follow-up guidance and complete UUID examples. Preserve the existing JSON envelope and run fields while adding result.runId.
Keep scheduling, persistence, request count, and SSH owner fencing unchanged. Isolate CLI output tests from inherited connection selectors.
Fixes#27542
* fix(runtime): a moved shell history waits only on this machine's shells, and a phone clears a server-owned copy's own unread flag
The migration's live-shell check counted a same-id SSH twin's pane, so a local history could wait
indefinitely. readAndHoldPhoneSession read a runtime: host as this machine and cleared the local
twin's record instead.
* fix(runtime): a phone clears neither copy of a twinned workspace; the history wait reuses the PTY host fence
* fix(native-chat): name the request a chat start ran out of time on, and log the original start error
A start that failed because a provider request hit Orca's deadline (e.g. Codex
thread/start after 30s) now says so instead of the generic couldn't-start
banner. The deadline marks its error with the method and timeout; the start
failure fact carries them as an optional requestTimeout field, and the host
logs the original error, method and elapsed open time.
* fix(native-chat): neutral start-timeout wording; log only the current child's failure, without timing in the repeat key
* wip(status-bar): remote empty usage state names the host and opens its accounts
* fix(status-bar): keep this computer's providers visible as "Not set up on <host>" under a remote workspace
* test(e2e): paired client keeps a this-computer-only provider as a host-named placeholder
* fix(status-bar): place usage placeholders only on the host's own 'unavailable' answer and open Settings on the owning host
* fix(status-bar): label the not-set-up placeholder chip "Not set up" instead of "--"
* fix(status-bar): placeholder only on a not-set-up reason; compact chip keeps "--"
* fix(status-bar): word the placeholder "Not configured on remote host"
* fix(status-bar): name the host in placeholder chips and keep Claude as 'No usage from <host>'
Only the host name truncates, so the phrase stays readable in every locale.
Claude set up here shows a placeholder when the host reports no OAuth login,
which reads the same as API-key billing, so it never says 'not configured'.
* test(status-bar): cover the Claude 'No usage from <host>' chip end to end
Pins USER on both apps so the runner's real Claude Keychain login cannot leak into
the host or client, seeds a refresh-token-only login on the client, and checks the
chip, its tooltip, the popover row, and that the chip goes away without Claude here.
* refactor(status-bar): share the owner placeholder snapshot and drop a dead Claude check
* fix(status-bar): build the owner placeholder tooltip in the current language
---------
Co-authored-by: E2E Test <e2e@test.local>
A hidden worktree is display:none, so ResizeObserver reported every mounted
diff row as 0px and the virtualizer cached that. Rows above the viewport
collapsed, and the unchanged scrollTop showed files two rows further down
after each switch back. Keep the last real row size while the scroller has
no layout box, and skip Monaco height reports from a hidden (0-width) editor.
Tab-scoped combined-diff view keys include the tab id, which is fresh for
every opened tab, so closing "All Changes" and reopening it (View all or
reopen-closed-tab) always started at the top. A fresh tab now inherits the
latest view a closed tab left for the same diff in the same workspace.
Views of mounted viewers or still-open inactive tabs are never taken, the
entry is moved rather than copied, and older closed views of that diff are
dropped.
* fix(codex): keep Orca's terminal identity in Codex commands under a filtering shell_environment_policy (#25775)
With inherit = "core" in a user's Codex config, every command Codex runs lost
ORCA_TERMINAL_HANDLE and the other ORCA_* values, so orca orchestration commands
failed with no_active_sender_terminal. Orca's codex shell function (bash, zsh,
fish, PowerShell) now passes those identity keys as per-launch
shell_environment_policy.set overrides, which Codex applies after its filter.
Skipped when the user opted into Codex's shared server, since Codex treats any
-c as opting out of it. The CLI error now names Codex's policy when it runs
inside Codex without an Orca identity. Daemon protocol 49 -> 50.
* test(windows): keep the node-as-codex Git Bash fixture free of forwarded identity
* fix(ci): keep the PowerShell wrapper inside its command-line budget; move the build contract to protocol 50; correct include_only advice
* refactor(codex): name the shared-server args for what they are; shorten the Codex identity error
* fix(codex): skip identity values holding an apostrophe instead of passing a truncated path
A TOML literal can't carry ', and Codex's fallback for the failed parse
truncates values such as /a' or /a' #b. Also drop the reversed key list
(order of distinct keys is irrelevant; tests now compare unordered) and
rename the host-side skip set to NO_DAEMON_SKIP_ARGS.
---------
Co-authored-by: E2E Test <e2e@test.local>
* feat(ssh): let a nodejs.org mirror serve the pinned Node on both machines
* fix(ssh): share one deadline across every host download URL
* fix(ssh): give each host download URL its share of the deadline and cap its size
* refactor(ssh): one tool per host, labelled sources and a portable wget watchdog
* fix(ssh): quote this computer's short download reason in the combined error
* fix(ssh): fetch only validated mirror URLs on the host
* fix(ssh): drop an empty query or fragment from the mirror URL
* fix(ssh): keep a cancel or a local error as it is after the mirror fails
* feat(accounts): save MiniMax and GLM Coding Plan keys on the Settings host
The usage poller on an SSH, `orca serve` or paired server reads these keys from
that machine's ~/.orca, but Settings could only write them on this computer, so
those hosts never showed the meters. New accounts.* RPC methods (advertised as
accounts.usage-credentials.v1) save, clear and report the keys on the host and
refresh its usage. Settings routes the MiniMax and GLM sections, and their
endpoint/site settings, to the host picked in the page; an older host is asked
to update instead of the key being saved locally.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(accounts): a host whose desktop owns its accounts refuses usage keys instead of storing them unread
A WSL host's server has no usage poller, so a key saved there was reported
saved yet never read. Every usage-credential method now throws the same
desktop-owns-these-accounts message as the other account methods, and the
host stops advertising accounts.usage-credentials.v1.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(accounts): a paired client never overwrites a usage key the other Orca app on that machine sealed
The desktop app (safeStorage) and orcad (its own host key) share ~/.orca but
cannot open each other's sealed files. A remote save or forget of a MiniMax or
GLM key that this host cannot read is now refused, and the status reports it so
Settings locks that key and says to change it in the other app. Blank keys now
fail parameter validation.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(accounts): only blame the other Orca app for a key it really sealed, and always allow forgetting
Any read failure was treated as "saved by another Orca app", so a corrupt file,
a permission error or a host that cannot decrypt at all locked the key with a
false message and refused Forget, the only recovery. The host now reads the file
itself: only a well-formed encrypted envelope that a working store cannot open
counts as sealed elsewhere and blocks Replace; anything else is reported as
unreadable and stays editable. Forget is always allowed, and the check logs
nothing per status poll.
Co-Authored-By: Claude <noreply@anthropic.com>
* test(e2e): fail clearly when the orcad slot is missing instead of passing null as the program
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(settings): name the host in remote key descriptions, give the MiniMax API key its own failure toast, and treat malformed sealed files as unreadable
---------
Co-authored-by: Jinwoo-H <e2e@test.local>
Co-authored-by: Claude <noreply@anthropic.com>
* fix(native-chat): link Antigravity sign-in notices to settings
* test(native-chat): use typed failure sentences in settings link coverage
* fix(native-chat): put Antigravity settings link in sign-in sentence
* fix(worktrees): a sort order and a minted push remote land on the copy that named them, not skipped for a twin
The renderer already knows each id's host when it splits a sort order; it now sends it
(an optional parallel hostIds; older peers ignore it and keep the skip-twins rule). An IPC
git handler knows the host it required, so a minted push remote records on that copy.
* fix(worktrees): a twinned repo re-lists instead of an id-keyed sort patch; client hosts must name a registered repo
* fix(worktrees): a sort order naming an unregistered host skips that id instead of falling back
* fix(worktrees): a moving project's sort order is fenced before any host-qualified read
* fix(worktrees): a client's local sort-order host matches this server's own runtime stamp
* fix(worktrees): an exact host match wins before the own-runtime alias
* fix(worktrees): terminal-spawn materialization serves only a local row and records on the local copy
* test: drop casts from the spawn twin tests
* fix(worktrees): adopt evidence and the spawn hook stay on their host; an unmatched local keeps the id-only rule
* fix(worktrees): adopt evidence reads the host's own metadata rows
* fix(worktrees): reusing a same-URL remote reads ownership from this host only
* fix(worktrees): a server's own runtime-stamped row still materializes its push remote
* fix(runtime): a failed orphan adoption write rolls back instead of keeping the adopted tabs
The adoption rollback ran outside the store's durable transaction, so the store
rebased it like a stale renderer write below the topology fence and kept the
adopted tabs, layouts and incarnations; the next save then persisted them.
Run the adoption through runDurableMutation, whose rollback phase skips that
rebase, and refuse if a queued write changed the session it was checked against.
Co-authored-by: Claude <noreply@anthropic.com>
* fix(runtime): an adoption into an unwritten host partition is not refused as a conflict
Co-authored-by: Claude <noreply@anthropic.com>
* test: run the orphan adoption rollback test in the SQLite runtime project
Co-authored-by: Claude <noreply@anthropic.com>
* refactor(runtime): check and write an orphan adoption inside the store transaction
A snapshot comparison could not see a queued binding write that edits the
session in place. Plan the adoption against the session the transaction
reads instead, so queued writes are validated against rather than guessed at.
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>