* fix(ci): background steps are single run steps, so no JavaScript action reads the event payload while the runner rewrites it
* test(ci): guard the background slot cap and pin the payload-free allowlist
* fix(persistence): repo-row store writes take the row, not the id; ratchet the rest (R4-2a)
* fix(persistence): host-filter the runtime nested import; widen the id-only write ratchet (review)
* fix(runtime): nested import keeps matching runtime-stamped native rows on a paired host
* fix(persistence): class-scope the ratchet param exemptions; update a new main test to the target shape
* fix(ipc): fence a project-group move by the resolved twin host, so an SSH twin is not WSL-fenced
* test(ci): pin the id-only store write ratchet step to the static phase
* refactor(pty): every PTY retirement names its exit proof; ratchet the unproven ones
* refactor(pty): count raw ownership drops, route an abandoned relay stop to unverifiable, honest proof labels
* fix(relay-ops): let same-cap rolls run while another cell is reserve; refuse a reserve roll target by name
The director refuses cell-status for a step-5 reserve cell with a 404
{error: cell_in_reserve_mode}. The same-cap headroom check read it for
every general cell, so any roll failed while c7 was reserve. A reserve
cell that is not being rolled now counts as no free slots (its seats are
not in the database) and is listed with reserve: true. A reserve roll
target, in the headroom check, the same-cap job's first cell-status read
and the candidate tool, now fails with the design's procedure: flip it to
admitMode=db first, roll, then flip it back. Any other 404 still fails.
* fix(relay-ops): pin the headroom gate's imports as evidence code; name both cells in a two-cell reserve refusal
* ci: run the layout-owner switch-on specs as an advisory PR job
Build the e2e app with ORCA_LAYOUT_OWNER=main through the existing e2e.yml
(new layout_owner input, read only by the app and orcad builds), run the
layout oracle, its positive control and the layout-owner acceptance specs
with the save-divergence log on, and upload a summary by kind and spec.
Not in the PR aggregate's needs.
* ci: summarize divergence logs without a test report, and drop file-path ids from kinds
* ci: switch-on job adds the stream-loss spec and the managed-SSH Docker lane, drops diff-word-wrap (fails switch off), and names each looped test in the summary
* test(e2e): editor-model-host-isolation opens both files through the store's open action, so a layout-owner build's main holds the tabs
* ci: the divergence summary skips a cut-short test report instead of failing
* ci: re-run PR checks on a merge ref that includes the main typecheck repair (#30680)
* feat(relay): add the per-cell phonePath switch, effective only in reserve mode
Step 6 of the relay redesign keys every phone-path change on this switch. The cell
reports the effective value in runtime status, and the flag tool refuses phonePath=memory
unless the cell is reserve, and a reserve flip that would turn phones over unnamed.
* feat(relay-ops): watch a memory phone cell and turn its phone path off on a breach
The reserve watch now also judges five phone rules while the switch file says
phonePath=memory, from the cell's own runtime metrics against the 10 minutes before
flipped-at: 4401s, confirm failures, attach-deadline 4404s and accept database errors
over their lines for 3 minutes, and completed accepts under half of background. A
phone-rule trip writes phonePath=db only; any other trip still flips the cell back
whole. Resume audit drops page after 5 minutes and flip nothing.
* fix(relay-ops): store phonePath=db as no key, so old images keep taking writes
An explicit phonePath=db left in the switch file would make the flag tool refuse every
later write after an image rollback, including a watcher's admitMode=db flip back.
* fix(relay-ops): keep phone watch rules off traffic noise, and keep watching after a phone trip
Completed accepts are no longer judged. Rate lines use the background mean plus
max(margin, share, 4 Poisson deviations), with a margin of 3 for attach deadlines. A
phone trip writes phonePath=db mid-watch and the reserve rules go on; both flip backs
remove the phonePath key so a cell rolled back to an image without it takes the write.
The phone background starts where phonePath went memory, and a background broken by a
restart refuses the watch. Audit drops page only while rising; failing renewals page too.
* test(relay-ops): replay the phone rules on 26 recorded hours of c7 and c29
Per-minute counts from the cells' runtime metrics (read-only, 10-18/19) replace the
synthetic quiet window. c29's bursty auth failures tripped the attach-deadline rule at a
margin of 3 in 29% of 300-minute watches, so its margin is now 5 like the others.
* fix(relay): judge the phone rules as a share of attempts, retry a failed phonePath write
The count rule false-tripped busy c28 (33/121 five-hour watches). The share rule (over half of
the minute's attempts, 0.25 over the background, capped at 0.6) trips none of the recorded c7,
c28 and c29 watches and catches two refusals per accept within 3 minutes. A failed mid-watch
phonePath=db write now keeps watching, retries each sample and pages after 3 failures; break
glass also drops phonePath.
Co-Authored-By: Claude <noreply@anthropic.com>
* docs(relay): cite the replayed c28 count-rule false trips
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(relay): judge phone confirm failures against completed accepts
Each completed accept makes one confirm, so failures/(failures + accepts) could never pass half
and a total confirm outage never tripped. Confirm failures are now a share of accepts.
Co-Authored-By: Claude <noreply@anthropic.com>
* test(relay): note why the confirm replay tests only trips
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* feat(relay): add the per-cell phonePath switch, effective only in reserve mode
Step 6 of the relay redesign keys every phone-path change on this switch. The cell
reports the effective value in runtime status, and the flag tool refuses phonePath=memory
unless the cell is reserve, and a reserve flip that would turn phones over unnamed.
* fix(relay-ops): store phonePath=db as no key, so old images keep taking writes
An explicit phonePath=db left in the switch file would make the flag tool refuse every
later write after an image rollback, including a watcher's admitMode=db flip back.
* refactor(terminal): one PTY attribution for teardown, close and identity; delete the deprecated resolver pair
- strict ssh: route: a proven direct listing beats a same-id server proxy; other contradictions refuse
- terminal spawn's git branch takes the strict route when a host is named (rivals refuse)
- resolveTerminalPtyOwner + isUnattributedTwinWorktree replace resolveRuntimeOwnerForWorktree in
shutdown, pane and agent hibernation, and PTY identity; close logs unroutable runtime ids
- delete getRuntimeEnvironmentIdForWorktree/resolveRuntimeOwnerForWorktree (legacy branch moved
into the adapter), the alias golden test, the importer ratchet, its baseline and pr.yml step
- hasHostEvidence reads the owner indexes instead of scanning repos and groups
* fix(terminal): close and identity read spawn's attribution for unscoped remote ids (Opus P2)
- an unattributed twin's unscoped remote: id is skipped and logged on close, never closed locally
- setup terminals: identity and close follow spawn's runtime; raw-id teardown stays local
- drop the last stale getRuntimeEnvironmentIdForWorktree mock (tests/e2e unit suite)
* refactor(terminal): one ownership read in resolveTerminalPtyOwner
* test(terminal): pin the close-path twin skip and the two-proxy direct listing (Opus P3)
* test(terminal): keep the close-provider owner fixture's full union type (Codex P1)
The root moved to pnpm 12 in #17156 but these two isolated workspaces were
left on pnpm 10, so CI and deploys carried a second pnpm and pnpm/action-setup.
- Pin the root's integrity-checked pnpm 12.14.0 and regenerate both
lockfiles (only the pnpm 12 package-manager document is added; the
dependency graph is unchanged).
- Move settings pnpm 12 ignores out of .npmrc and package.json#pnpm into
each pnpm-workspace.yaml; onlyBuiltDependencies becomes allowBuilds, and
cloud keeps esbuild's script skipped as pnpm 10 did. package-manager-strict
is gone in pnpm 12, whose own version pinning supersedes it.
- docs/site drops --ignore-workspace: under pnpm 12 it skips the workspace
file, losing the overrides and failing the frozen install. vercel.json now
pins install/build so a stale dashboard command cannot reintroduce it.
- Cloud and docs workflows use pnpm/setup@v2 like the root; the relay
unit-test step uses the root's pnpm instead of npx pnpm@10.
* test(browser): expose native popup admission blockers with faithful app events
* test(browser): probe Electron popup identity and inherited sandbox API limits
* test(browser): handle requests without associated contents in popup probe
* docs(browser): record blocked Electron popup compatibility gates and test routing
* docs(browser): keep popup evidence in PR
* test(wsl): exercise structured chat on real guest hosts
* test(wsl): keep chat contract within the module size limit
* test(wsl): use braced conditions in chat lane
* test(wsl): configure the fixture through host launch settings
* test(wsl): keep cancellation assertion at the RPC boundary
* test(wsl): avoid assuming cancelled turn publication timing
* ci(wsl): run guest chat coverage for Claude environment changes
* test(ci): match the WSL lane's merged unit-test exclusion
* ci(wsl): drop lane trigger paths that no longer exist
* ci(wsl): run the WSL lane when the shared process-host package changes
* refactor(ssh): split ssh-connection-utils into concretely named modules
- classifiers -> ssh-reconnect-error-classification.ts
- retry/timeout constants and sleep -> connection/ssh-connection-timing.ts
- buildConnectConfig -> connection/ssh-connect-config.ts
- credential callbacks -> connection/ssh-connection-callbacks.ts
- exec options and abort error -> connection/ssh-exec-options.ts
- wrapRemoteCommandForPosixShell -> ssh-posix-command-wrapper.ts
- shellEscape and shared/wsl-login-shell-command quotePosixShell (identical) -> shared/shell-argument-quoting.ts quotePosixShell
No re-exports are left behind.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: point the WSL git benchmark and the WSL lane route at shell-argument-quoting
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* build: share one pnpm virtual store across worktrees, off under CI
Each worktree carried a full node_modules; the global virtual store links
one slot per package version instead. pnpm keeps an explicit setting on
under CI, so a pnpmfile hook turns it off there: CI packages from,
caches and verifies a project-local node_modules.
* fix(build): keep shared electron and windows-process-tree dirs untouched under GVS
Every worktree runs Electron from the one shared electron package, so the
per-repo dist cache must not swap that dist and a foreign-arch install must
not land in it. The relay addon builder now repairs and compiles a private
copy instead of the shared windows-process-tree dir.
* fix(build): accept CLI runtime imports reached through an in-artifact store link
Under the global virtual store node_modules/<pkg> realpaths into a store
outside the repo. The check still rejects anything not reached through a
node_modules link inside the artifact, such as a stray ~/node_modules.
* docs: explain the global virtual store layout and the ~/node_modules hazard
* test: compare CLI closure paths with POSIX separators so the suite passes on Windows
* build: keep Windows on the normal pnpm layout unless ORCA_PNPM_GLOBAL_VIRTUAL_STORE=1
Store links are true symlinks on Windows, and installs without admin or
Developer Mode are unverified; CI still forces the normal layout first.
* fix(build): close the remaining shared-slot gaps under the global virtual store
- verify-skills-cli-runtime resolves each import from the importer's realpath,
as Node does, so an artifact-local copy can't mask a ~/node_modules load.
- A concurrent sibling install of the shared Electron dist is kept, not swapped out.
- rebuild:node goes through ensure-native-runtime, which builds a shared
node-pty beside the slot instead of node-gyp cleaning its build/ dir.
* fix(build): keep pnpm rebuild:node a forced rebuild
It replaced pnpm rebuild node-pty, which always rebuilt; without --force it
only rebuilt a node-pty that failed to load.
* docs: note that the store switches must stay set, since pnpm run relinks
* build: move the pnpmfile under config/ to keep the repo root allowlisted
pnpm-workspace.yaml points pnpm at it; the lockfile checksum is unchanged
because the content is.
* fix(build): enable the global virtual store from the pnpmfile, not the workspace file
pnpm exec derives NODE_PATH from the file setting, so even with the store
forced off under CI every child process got the root node_modules on its
NODE_PATH; a Windows rebuild fixture then resolved the real
@orca/windows-registry it deliberately omits. The hook now sets the store
both ways, and ORCA_PNPM_GLOBAL_VIRTUAL_STORE=0/1 is the one switch.
* test(pty): keep F3's concurrent spawns on the node-pty mock
Two concurrent first import('node-pty') calls race vitest's mock registry
and the loser loads the real addon under the mocked linux platform. It
passed only where a platform-agnostic build/Release happened to exist,
so it failed on every shared-store worktree.
* ci: fail PRs whose packages need a dependency they never declared
A new dependency_isolation job installs with the global virtual store
forced on (ORCA_PNPM_FORCE_GLOBAL_VIRTUAL_STORE_IN_CI), HOME and the store
in an empty temp dir, then runs pnpm tc and the undeclared-dependency test.
Postinstall now warns when a node_modules above the shared store, such as
~/node_modules, would mask the same class of bug locally.
* ci: set the isolation job's HOME and store through GITHUB_ENV
Job-level env cannot read the runner context, which made pr.yml invalid.
* fix(relay): judge the reserve watch's 503 rule on non-drain 503s, not a host's own re-dials
The watch counted every director 503, and on 2026-10-18 ~98% were host-rate-limited re-dials that
grow with traffic, so it flipped production-gce-c7 back twice with no fault. It now uses the roll
ladder's non-drain measure (request_count 503s less drain-return deferrals and host-rate-limited /
host-in-flight re-dials from the director's runtime metrics) for both the background and the live
samples. A judged minute no runtime-metrics line covers is unverifiable, not zero.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(relay): state the reserve watch's metrics coverage honestly and share the metrics read limit
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
12.10.1 repairs a global-virtual-store slot an interrupted install left
without dependency links (pnpm/pnpm#16642); 12.12 adds addMissingPeerTypes.
The CI store-mode and terminal-perf gates follow the pin they were measured
against, and mobile/ and config/audit-tools record the same pnpm.
* refactor(ssh): move the ssh-connection and ssh-target cluster into ssh/connection/ and ssh/targets/
Pure git mv plus import and path-literal rewrites. ssh-connection-utils stays put; the next PR splits it.
Co-Authored-By: Claude <noreply@anthropic.com>
* test(e2e): keep the release-checkout import at the v1.4.218 path
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
orcad-state-*, orcad-windows-host-* and orcad-machine-* leave src/main/ssh. git mv plus import and
path-literal rewrites, including the Windows host lane's test path in its workflow and PowerShell
runner.
orcad-remote-*, remote-install-*, remote-node-runtime-store-*, remote-versioned-install and
remote-deploy-timing leave src/main/ssh. git mv plus import and path-literal rewrites; one e2e route
regex learns the new folder. orcad-remote-deploy and orcad-remote-node-runtime-report stay for now
because open PRs #29834 and #29829 edit them.
* fix(mobile): break the transport and terminal-document import cycles and gate them after mobile's install
client-context re-exported the host-client hooks, which import client-context back: the re-export
barrel is gone and importers (and their test mocks) name host-client-hooks directly. In the terminal
document, the cell-metric getters move to a leaf cell-metrics module and select-mode entry/exit to
selection-mode, so fit, transform, overlay and range no longer import each other. pr.yml lints imports
before mobile's install, when mobile's tsconfig can't load, so Mobile verify now runs the same import
rules over mobile after its install with zero warnings allowed.
* fix(mobile): the browser-pane render harness imports useHostClient from host-client-hooks
Its route source is a template string, so no typecheck saw the removed client-context re-export; the mobile web bundle check did.
* fix(ci): the e2e typecheck ratchet counts the same with or without mobile's install
Specs reach mobile/src/transport, whose expo-crypto and async-storage imports resolve only after mobile's install and then load React Native's globals (numeric timers, a required NODE_ENV), adding errors in unrelated specs. An empty stub pins both, so the static job reads 232 either way.
First slice of the desktop side of managed orcad leaving src/main/ssh. git mv plus import and
path-literal rewrites; host-lane workflow filters and the cross-host prefix list gain the new folder.
Moves legacy-relay-bridge/ plus the relay-only census and endpoint files into ssh/legacy-relay/,
so the 2027-01-15 retirement deletes one folder. Live install, exec and framing modules that only
carried the relay name become remote-*. git mv plus import, path-literal, routing and workflow
path-filter rewrites only; no remote file name or path changes.
tests/ is typechecked by nothing in CI, so the Windows CLI matrix spec imported a helper that never existed (#30231). Per-file error counts under tests/ (tsc -p config/tsconfig.e2e.json) may now only go down.
Worktree ids built as `${repo.id}::${path}` by hand are how one worktree got two
spellings (#30150). New code composes them through src/shared/worktree/id.ts; the
ratchet counts the remaining hand-built ids per file (18) and may only go down. Six
byte-identical `${repo.id}::${repo.path}` sites move to getRepoMainWorktreeId.
* ci: ratchet src/ path literals in CI config, workflows and e2e code that name no file
* ci(path-literal): resolve relative imports exactly
* ci(path-literal): resolve against tracked files only; read ./src imports
* ci(path-literal): scan src/packages and src/types references too
* ci(path-literal): skip paths quoted in comments
* ci(path-literal): keep a recursive glob's boundary
* ci(path-literal): strip comments with a string-aware scan; any import occurrence is exact
* ci(path-literal): imports need a module or index; relative globs and folders stay prefixes
* fix(mobile): wall hosts that cannot serve the page instead of opening native screens
* refactor(mobile): drop the native-route state and the shell fallback prop; unknown routes say unavailable
* test(mobile): read the nullable page route refusal in its policy test
* refactor(mobile): every build is the OTA shell; drop the native/OTA build switch
The owner retired the native-screen fallback with no emergency native build, so
EXPO_PUBLIC_MOBILE_SHELL, mobileShellBuildKind, shellSwitchDecision, the Metro
cache-key suffix and both release workflows' shell input go. Every host route
mounts the shell; a route naming no screen the shell could open gets the
existing refusal screen instead of a native screen.
Claude-Session: https://claude.ai/code/session_6cea92f6
* refactor(mobile): drop the dead web route, flag-era comments and the one-value shell kind
The host route files no longer switch, so their comments say what they do now:
a route naming no screen shows the unavailable screen. app/h/[hostId]/web.tsx
duplicated index.tsx and nothing linked to it, so it and its stack entry go
(the bundle sweep is re-measured: 77 scripts at 15 routes). Diagnostics print
the bridge protocol on its own instead of a shell kind that has one value.
Claude-Session: https://claude.ai/code/session_6cea92f6
* chore(ci): ratchet renderer importers of the deprecated runtime-owner resolvers
getRuntimeEnvironmentIdForWorktree and resolveRuntimeOwnerForWorktree read a
worktree two hosts publish as not-a-runtime, which callers treat as local. The
62 renderer files importing them are grandfathered; the list may only shrink.
* ci: register the deprecated runtime-owner ratchet step in the preflight phase map
* feat(orcad): ship the mobile web page so phones paired to orcad get it
orcad never carried out/mobile-web, so it did not advertise
mobileWeb.bundle.v1 and phones paired directly to an orcad server fell
back to the app's built-in native screens.
The built page now ships in every orcad package at out/mobile-web, the
path getBundledMobileWebBundleRoot already probes under the install
root. Its manifest is a fixed artifact; its content-addressed assets
join the hashed artifact list from that manifest, as one shared copy in
the template's common files. build-orcad fails when the page is missing
or stale, and CI lanes that build orcad now build the page first.
* ci(orcad): check out mobile/ for the Windows host template build
* refactor(orcad): copy the page tree whole and build it once per CI run
The guard already refuses unlisted files, so staging copies the
bundle directory as native-chat-visuals is copied. The shipped template
takes the page the qualification lanes tested, the e2e build artifact
carries it, and the PR smoke builds it through install-mobile-dependencies
behind its own scope step. Drops tests that duplicated the guard's own.
* fix(orcad): refuse a template page asset name that escapes the slot
* ci: build the WSL server template once
* ci: reuse validated Windows native addons in E2E preparation
* ci: avoid the unused standalone server build in SSH E2E shards
* ci: remove Windows build and persistence test overhead
* ci: collect unit phase diagnostics during PR checks
* test(ci): seed hook reuse fixture from the canonical prebuild
The hook reuse regression first built into a missing private --output, so it
always reached Cargo (74s warm on Windows). Build through the default output
instead, which reuses a warm canonical prebuild, then copy its executable and
fingerprint into the private fixture root.
* fix(lint): clear inherited max-lines and broad object tab parameter after main merge
Combine the duplicate shared/execution-host imports in runtime-host-services
(301 -> 300 lines) and type the overlap test's tab mapper with the
RuntimeMobileSessionClientTab owner type instead of object.
* fix(ci): align inherited runtime and workflow contracts
* test: establish changed runtime probe signatures deterministically
* test: await asynchronous daemon profile cleanup
* test: shut down owned daemons before deleting profiles
* test: clean up oracle daemons during final app close
* test: recognize verified Linux zombie exit during daemon teardown
* fix: preserve folder SSH ownership when project groups conflict
* ci(wsl-orcad): skip the WSL MSI when the image already has 3.0.1
windows-2025 image 20261007.264.1 ships WSL 3.0.1.0, and reinstalling the
pinned 3.0.1 MSI over it exits 1603, failing every run. Install only when the
image is older, print the msiexec log on failure, and gate on >= 3.0.1 after.
* fix(orcad): let a managed launch fall back when its default port is taken
#29432 made any --port mandatory, but managed SSH/WSL launches pass the
default 6768 as a preference and read the bound port from readiness. WSL2
distros share one VM loopback, so a second distro's orcad now failed with
pinned_port_unavailable. Only an operator --port is required now.
* [CI] Keep transport-only tests outside the app store graph
* [CI] Advance the updater install clock in failure tests
* [CI] Avoid descriptor formatting in replay clip counts
* [CI] Advance native-chat test observation clocks
* [CI] Restore observation timers after failed test setup
* [CI] Clean up final headless daemons during public close
* [CI] Keep serializer test oracle out of production smoke triggers
* [CI] Keep three unit fixtures out of production smoke triggers
* [CI] Bound frozen-clock close callbacks in tests
* [CI] Avoid the app-store graph in feedback dialog tests
* [CI] Keep hidden popup fixture compositor frames active
* test(ci): reuse mobile runtime fixture for pairing listeners
* test: restore native chat clocks before rig cleanup
* fix: render Kitty Unicode placeholder images with bounded ownership
* Enable managed Claude plugin images and bounded host file transport
* Preserve isolated Claude evidence and paired restart diagnostics
* Resolve Windows workspace aliases before WSL image reads
* Handle split remote terminal identities and improve WSL file-read diagnostics
* Reuse native drive paths for WSL image files and preserve guest temporary roots
* Apply native Windows path restrictions to mapped drive image sources
* Preserve WSL participation evidence across image checks
* Keep WSL drive directory containment case-sensitive after canonicalization
* Negotiate managed Claude image support with the launching renderer
* Make image repaint checks independent of display profile and shell output
* Capture repaint diagnostics only after the pixel assertion fails
* Allow floating terminal image reads from host temporary folders
* Keep image stack independent of unrelated CI runner and mobile lint settings
* Reuse worktree argument builder for terminal viewer context
Remove duplicated mapping and keep the RPC method table within its existing line limit.
* ci: report final PR checks outside the shared runner queue
* ci: fix inherited mobile test file size failure
* ci: move PR analysis and ARM test shards to Blacksmith
* Qualify x64 Blacksmith capacity and reject incompatible runner images early
* Keep extracted mobile test adapters within the test-only lint scope
* Identify the runner profile overriding shell fixture homes
* Preserve fixture HOME through the Blacksmith login profile
* Make cache invalidation fixtures observable within one filesystem clock tick
* Scope Blacksmith system-profile preparation to Linux runners
* Wait for observable ctime in daemon hash cache fixtures
* Use the mobile test lint scope already merged on main
* Stabilize metadata and timer fixtures on fast CI runners
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* ci: report final PR checks outside the shared runner queue
* ci: retain the mobile harness test mock allowance
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>