Repository navigation
sync: merge stablyai/orca main (2026-10-10) into fork-main - #15
Merged
Merged
Conversation
* Use catalog snapshots for native chat workspace reads * Resolve native chat workspace directories from the catalog snapshot - Stop falling through to folder-path parsing once the catalog is loaded. The fallthrough let a folder workspace on another host resolve to a local path. - Look up model discovery settings by the worktree's runtime owner instead of the agent tab's, so a session's model list matches the worktree it runs in. * commit * Use worktree owner settings for native chat model discovery * Resolve native chat files from catalog snapshots
…al rules (stablyai#26673) * test(terminal): check the runtime's workspace layout against structural rules A pure rules check over the runtime's session partitions: a terminal in two panes, a pane in two tabs, a tab outside exactly one group, tab rows and tab bar disagreeing, two tab orders, and ids changing for the same pane, tab or group across an update. Wired into the seeded layout model test after every step, plus late-spawn cases (one known on main, kept as an expected failure). * test(terminal): check layout rules on every write and race client commands with the window The layout model now checks the structural rules on every in-memory workspace-session write, not only at each step's end, naming the writer of any breach. Three documented two-writer transients (main mints a tab row before the window writes its tab bar) are allow-listed by rule, op and writer; they must still heal by the step's end. New model ops race a stale window save against a paired client's tab close, a host-created split, and main's PTY-exit retirement. A new file runs main's updateMobileSessionPaneLayout (old phone pane trees) against the real Store; the case with no topology revision is an it.fails: main drops a live pane and its binding there.
stablyai#26674) * test(terminal): check the runtime's workspace layout against structural rules A pure rules check over the runtime's session partitions: a terminal in two panes, a pane in two tabs, a tab outside exactly one group, tab rows and tab bar disagreeing, two tab orders, and ids changing for the same pane, tab or group across an update. Wired into the seeded layout model test after every step, plus late-spawn cases (one known on main, kept as an expected failure). * test(e2e): layout oracle scenarios with window, headless serve and SSH Drives layout journeys through window gestures, CLI and paired-client runtime commands, and after every step checks the runtime's layout against the structural rules, the window's DOM, the paired-client and CLI views, the expected end layout, restarts (relaunch, cold daemon, in-app daemon restart) and per-pane terminal markers. Findings main still has are listed with their cause; anything else fails. Includes headless orcad/Electron serve scenarios for the serve issues and a Docker SSH scenario. * test(terminal): check layout rules on every write and race client commands with the window The layout model now checks the structural rules on every in-memory workspace-session write, not only at each step's end, naming the writer of any breach. Three documented two-writer transients (main mints a tab row before the window writes its tab bar) are allow-listed by rule, op and writer; they must still heal by the step's end. New model ops race a stale window save against a paired client's tab close, a host-created split, and main's PTY-exit retirement. A new file runs main's updateMobileSessionPaneLayout (old phone pane trees) against the real Store; the case with no topology revision is an it.fails: main drops a live pane and its binding there. * test(e2e): oracle expected outcomes, transient sampling, remount counts, more scenarios, latency Every step checks the expected panes, which panes went away and that the rest kept their terminals; a 100 ms sampler runs the rules between steps; xterm creations are counted per pane and an unexpected recreation fails. Adds host navigation, window reload (graph republication), quit right after a change (quit-time save), an old client's stale pane tree, and a latency measurement (command to drawn update, idle and under an output flood; no pass/fail). * docs(e2e): describe the oracle's added checks and latency measurement * test(e2e): stablyai#12723 SSH folder scenario, CI lane for the SSH oracle spec, short socket dir Adds an SSH folder-workspace (no repo) scenario that checks the layout lives in one partition across relaunch; registers the SSH oracle spec in the Docker SSH lane's selection lists; headless hosts put long-TMPDIR profiles under ~/.orca-lo instead of /tmp. * ci(e2e): run the headless layout oracle in the job that builds orcad; Linux relaunch findings The headless oracle spec needs out/orcad, which only the orca serve mode-switch job builds, so it runs there (and fails rather than skips in CI if orcad is missing). Records what the first Linux CI run found on main: after a relaunch main can hold tab rows with no tab bar past the settle wait, and Electron serve on Linux also lists a renamed terminal's title as null after a restart. * test(e2e): join partition lists in the SSH folder scenario's log lines * test(e2e): retry the latency spec's reads through a brief terminal-ownership gap Linux CI saw terminal.list answer terminal_surface_ownership_unavailable while the window re-published its terminals; reads retry for up to 10 s, commands do not.
…6653) * feat(native-chat): add a chat-owned command receipt store Adds the agent_session_command_receipts table and an insert-if-absent receipt write that runs inside a command's own journal transaction. A receipt records the command's identity, canonical hash, status and a pointer to the row holding its result; it dies with its chat record. Nothing uses it yet: the existing operation ledger stays authoritative. * fix(native-chat): key command receipts like today's ledger ids Rows are keyed by caller and operation id; a send looks across callers and other methods look up only their caller's row, matching the existing ledger. Bad rows and newer table shapes read as unreadable instead of throwing. * fix(native-chat): order receipt lookups by insertion and key by operation id Global lookups now take rows in insertion order, so a read and an insert agree on which receipt answers an id regardless of the host clock. The primary key leads with the operation id, so its own index serves both lookups.
…tablyai#26705) * Offer Resume in New CLI / Native Chat from the tab menu Right-clicking a native chat tab now offers "Resume in New CLI", and right-clicking a terminal tab running Claude or Codex offers "Resume in New Native Chat": the same items, gating and handlers the Session History row menu uses. The tab finds its Session History row through the existing mappings (the chat tab's session id against the row's structuredSession, and a terminal tab's agent-reported provider session, the mapping tab titles use, against the row's agent and session id), read from the Session History list scoped to the tab's workspace and host. Both surfaces now share one gate, resolveAiVaultSessionSurfaceSwitchTargets, one menu-item component, and call handleResumeInNewCli / handleResumeInNewChat from useAiVaultSessionLaunchActions. * Share the Session History list request with the tab menu's chat/CLI move The tab menu looked its history row up with its own list request, so it never shared the panel's cached list (and evicted it), forced a full rescan on every miss outside the panel's rescan budget, and inserted the item above Pin/Close seconds after the menu opened. - One list request (scope paths, depth, host, Antigravity flag) and one renderer-cache read/write, used by the panel and the tab lookup; the tab builds the panel's own request for its workspace. - A warm menu answers from the panel's cached list at first paint with no IPC; a cold one sends the panel's non-forced request and keeps its result in the panel's cache. - A forced rescan on a miss now takes the panel's shared forced-rescan budget; no other force. - No lookup on hosts where neither move can ever be offered (non-local). - The item moves to the end of the menu, so a late insert shifts nothing. - The panel and the tab compose the row's resume inputs through one function; parity is pinned by unmocked tests. * Revalidate the tab menu's chat/CLI move and allow it for remote-server chats - The cached first paint is always replaced by the fresh list answer, so a conversation a chat has since taken no longer offers Resume in New Native Chat from a stale cached row. - Native chat tabs in a remote Orca server workspace look their row up on that server (it projects chat ownership), so Resume in New CLI shows there as it does on the row. CLI tabs stay local-only; SSH stays skipped. - A menu that closed between the two list calls no longer starts the forced rescan or spends the shared budget; forced rescans stay local. * Keep the tab menu's history lookup from writing the panel's result cache A tab lookup wrote its list into the Session History panel's renderer cache, so a panel opened afterwards could paint that pre-launch list without asking the host and show a chat-adopted row under its old title. The tab now only reads that cache for its first paint; the host's cached list is already shared through the identical request. * Offer the tab menu's chat/CLI move only from a fresh history answer The panel's renderer cache never carries current chat ownership (the host projects it per reply), so painting the menu item from it first flashed "Resume in New Native Chat" on a terminal tab whose conversation a chat had taken, and missed the move on that chat's own tab. The item now appears only once the fresh (non-forced) list answer lands. * Put the tab menu's chat/CLI move above Pin Tab and hide Switch to chat view
…grade tip (stablyai#26710) * feat(native-chat): one-time upgrade tip for pre-upgrade Experimental Chat UI users Show the new native chat upgrade tip through the normal startup feature-tip flow, only to profiles whose saved Experimental Chat UI setting was on before this release. Main records that audience once, from the profile as saved by the previous build, and never re-derives it from the live setting, so later opt-ins, new installs and the future graduation stay excluded. * fix(native-chat): keep the upgrade tip readable and dismissed Focus Got it without scrolling and tighten the ja/es/fr copy so the title is visible on open. Show the tip exactly like other startup tips (no resume-dialog wait), keep the illustration's upward menu unclipped, and merge seen tip ids on save so a stale client cannot bring a dismissed tip back. * fix(native-chat): say "between chat and CLI" in French and pin the audience basis in tests
* Native chat: Cmd/Ctrl+F opens find in window Mod+F inside a focused native chat opens a find bar at the chat's top-right corner. The bar is a separate sandboxed view stacked over the main window, so its own input is never a match; main runs the window's find-in-page and relays the match count back. Enter/Shift+Enter step, Escape closes and clears. Also stops the terminal search bar from opening over a chat that covers a terminal pane. * Native chat: Cmd/Ctrl+F finds inside the chat transcript Replaces the window-level find panel with a find bar inside the chat. The panel searched the whole window, pasted into the composer, outlived its chat, and let Escape interrupt the agent. - Searches only the transcript text the reader can see and paints matches with CSS highlights, reusing the markdown preview's search, now shared as lib/dom-text-search-highlights.ts. - Re-searches as the transcript streams or scrolls, keeping the current match; a step leaves "follow latest" like a reader scroll. - Escape closes the bar first and returns focus; paste and editing keys stay in the bar's input. - Terminal guard yields any chat.find chord inside a chat cover; a PDF no longer takes Mod+F from another surface. * Native chat find: round-2 fixes - Escape: the chat root's React capture handler closes the bar before the composer's own capture handler can interrupt the turn. - One visibility rule for picking and revealing a match: typing no longer scrolls to a match that is already on screen, and the bar's real rect, not a full-width band, decides what it covers. - Reveal scrolls nested scroll boxes (code lines, tool output, thinking); text cut off by a box that cannot scroll is not counted. - PDF find opens from its own tab and the file explorer again, but not from another group, a chat, or a text field. - Prompt cards no longer take focus from the find input; clicks on the bar keep typing in it; buttons keep their own Enter. - A match whose row scrolled away restarts from the first visible match. - Streamed text growth re-searches every 120 ms instead of every frame, and searches reuse their Range objects. - Hover-only row chrome is marked and skipped instead of read by opacity. - Chat find stays off in the web client, where the browser's find keeps Mod+F. - The text matcher moves to lib/text-match-ranges.ts with neutral names. * Native chat find: round-3 fixes - Text that held a match re-searches before the next paint: React rewrites a growing text node whole, collapsing its ranges, so the streaming paragraph's highlights no longer blink. Other text growth keeps the 120 ms re-search. - A disclosure's height animation ending re-searches, so an output opened while find is open is counted. - A prompt card that arrived while the find bar held focus gets it when find closes. - A reveal that cannot scroll no longer stops following the latest. - PDF find follows the panel's chord owner (its tab is the active tab of the focused group, the rule the browser pane uses), so it no longer takes Mod+F from a chat, terminal or browser in another split, and it opens again after clicking its own editor header. * Native chat find: PDF find answers only its own window surface The floating workspace panel keeps its own focused group, so a PDF that owns its panel's chords no longer takes Mod+F from a chat in the other surface (main window vs floating panel), matching how the browser pane scopes a floating workspace's chords.
…lyai#26726) * Default status bar usage to Compact * Explain Compact usage to affected existing users once
* fix(orcad): provide execution host CLI in Unix managed terminals * fix(orcad): keep the server starting when the CLI launcher cannot be written --------- Co-authored-by: m4air <m4air@Mac.localdomain>
…i#26559) * Report browser placement capabilities from the installed provider * Run managed browser capability checks in the template-building CI lane
* fix(native-chat): read a queued card's whole text, and keep Edit from hiding it behind a prompt A queued card showed one clipped line, so a long message (often another agent's, never typed by the reader) could not be read before Steer or Delete. A clipped card now opens in place to its whole text; the phone's two-line card opens on tap. Edit moved the card's text into the composer and deleted the card even while a question or approval card stood in the composer's slot, so the text vanished from the page. Edit now waits, saying why, until the prompt is answered; the pane and the queue read one check for whether a prompt holds the composer's slot. * fix(native-chat): keep the full-text hover title on a folded queued card * fix(native-chat): phone card opens only when it clips; test the composer-slot check The phone card measured nothing and made every card a button; it now lays the text out unseen at its width and offers Show more only past two lines. The Edit reason is no longer dimmed twice, and the shared composer-slot check and the desktop toggle's keyboard reach have their own tests. * fix(mobile): the unseen measuring copy of a queued card takes no touches * fix(native-chat): open a queued card's full text below its row, at the card's width In a narrow chat the opened text sat beside the card's actions and wrapped a few characters per line. It now opens under the row, indented to the text, the way the transcript's awaiting-input row opens its question. * fix(native-chat): the queued card's toggle names the opened text only while it exists * refactor(native-chat): the queue reads pending prompts itself, keeping the session hook under its line cap * refactor(native-chat): keep this PR to reading a queued message in full; Edit moves to in-place editing * test(native-chat): queue list rig passes the pending-prompt flag main's controller takes
… logic (stablyai#26704) Sleeping-session resume, AI vault resume and the plain quick-command terminal each carried a line-for-line copy of persistAgentLaunchTabOrder. Call the helper instead. No behavior change.
…tablyai#26573) * Distinguish remote browser service failures from server outages * Use the shared browser_unavailable code in the stream failure classifier --------- Co-authored-by: m4air <m4air@Mac.localdomain>
…ai#26570) * Keep local browser routing on the deployment SSH host after conversion * Seed published SSH connection state in browser lifecycle fixture
…blyai#26581) Co-authored-by: m4air <m4air@Mac.localdomain>
…26584) Co-authored-by: m4air <m4air@Mac.localdomain>
) * Preserve editor file identity during SSH host conversion * Keep a dirty in-session editor tab on its file record during SSH conversion A file opened over the relay in the current session carries route provenance, so the no-host-evidence check repointed its tab to a fresh clean record and hid the unsaved draft. Keep any retained record with no runtime owner instead. --------- Co-authored-by: m4air <m4air@Mac.localdomain>
…lyai#26634) Folder rows used the bare folder ID for active state, DOM IDs, virtual keys and activation, so same-ID folders on two hosts collided. Use the existing host-qualified worktree identity, matching git worktree rows. Co-authored-by: m4air <m4air@Mac.localdomain>
…#26747) * Preserve usage-menu focus and polish the Compact notice * Restart usage notice delay when selected notice changes
…tablyai#26663) Co-authored-by: m4air <m4air@Mac.localdomain>
…26595) * Refresh rich Markdown links when document metadata changes * Type Markdown link storage for metadata refresh tests
…6666) Agents often answer a failed session/prompt with a generic JSON-RPC message ("Internal error") and keep the real reason in error.data. Only OMP and Grok had hooks that read it, so OpenCode and future ACP agents showed the bare message. The prompt error detail now reads, for every ACP agent: the agent's hook, else string data, else data.details, else the message. Other structured data is metadata and is ignored. OMP's details hook and Grok's string-data branch are now covered by that rule and removed.
* Refresh open Markdown document links after file changes * Use the stable Markdown refresh callback in the watcher effect
…yai#26743) * Show 'Pi isn't signed in' before the first send A Pi chat whose agent started with no model to use now says so in the existing availability notice, and the next send replaces that agent so a sign-in made since takes effect. * Re-read the sign-in notice when the chat's agent stops; ignore an exited Pi A Pi's start verdict ends with that Pi: the notice now re-reads when the host starts or stops the chat's agent, and a Pi whose process already exited reports nothing. * Keep one sign-in line after a refused send; re-read on every agent start or stop The notice steps aside while the newest send was refused for the same reason, and the chat re-reads its verdict whenever its agent starts or stops, dropping an answer read before. * Step the notice aside only while the refused send's own line is on screen Uses the host's send order and the chat's rendered delivery lines, so a deleted returned card or a trimmed row brings the sign-in notice back. * Keep the sign-in notice when the refused message is no longer loaded
Merges upstream main f307391 into the fork (supersedes #14). - Automations: the fork's per-automation extraArgs is renamed agentFlags (schema, save path, CLI --agent-flags, editor, i18n, RPC catalog, capability automation.agent-flags.v1); upstream extraAgentArgs and its allowlist are untouched. One-time idempotent load migration extraArgs -> agentFlags. Reuse-session refuses agentFlags. Per-automation model/effort/profile and agentFlags are carried into launchHeadlessAutomationAgent. - Relay: adopt upstream's installer; keep the fork's failed-start fencing, 1/5/15/60s install retry, 4401 force-refresh remint (now a sticky flag so a superseding reconcile still rotates), and fail-fast of in-flight drain work holding a revoked credential. - e2e: test.fixme the Set Title strip drop test (fails upstream since stablyai#26385; reverted fork fix ce52fe4 -> 49b6cfc).
8 of 10 tasks
Install fork AppImages under HOME with checksum and package marker validation, preserve the Fork-5 launcher and explicit /opt fallback, and document box persistence integration and isolated smoke evidence. Opt identified ensure-managed home AppImages out of in-app update checks, downloads, and installs so the saved release pin owns restoration.
feat(linux): pinned home AppImage installer and box ensure recovery
Point the home AppImage test at @orca/process-host, land the AppImage feature row, stub getAgentCatalog in usage-chip parity, and assert the shipped old-Windows WSL update notice on the wire downgrade path.
The serial 45-minute job cancelled on large upstream-sync file lists after 111 passing tests. Reuse the existing timing balancer so each shard keeps one Playwright worker, and empty shards exit 0.
The code_paths job only checks out ci-e2e-job-selection.mjs, so importing the timing balancer broke --job-outputs. Split the general spec list with in-file round-robin instead.
readDaemonPidFiles re-read a pid file in its catch path, so a file that disappeared after readdir threw ENOENT and failed orcad-serve-mode-switch on Windows. Read once and ignore leftovers, matching the packaged Windows discovery helper.
…l oracle The headful stall-recovery spec asserts the live marker is absent from xterm while ACKs are held. Automatic stream recovery painted the flood and marker first, so the assertion failed on changed-e2e shard 1. Pin the client to the existing disable query so only the ACK-gate restart can unstall the stream.
Disabling auto-recovery made the live-marker absence check stable, then the stream never restarted so LIVE: never painted. Expose the existing recoverStalledStream path on the e2e ACK gate and call it after release.
Static analysis flags type assertions on changed lines. Duck-type the e2e ACK gate through Reflect.get instead.
Anti-slop rejects Reflect.get, and consistent-type-assertions rejects `as`. Declare the e2e ACK gate on Window and use typed property access.
heldAckChars already proves ACK starvation. The one-shot not.toContain on the raw send raced in-flight PTY frames and failed changed-e2e shard 1. Keep the recover hook and the LIVE: / same-PTY oracle.
Codex in the same file reached GOLDEN_STUB_AGENT_READY; Claude hit the 20s waitForTerminalOutput cap on changed-e2e shard 3.
…n resize The changed-e2e 3-of-3 Claude launch set the Golden Stub Agent tab title and left a blank alt-screen pane. Prefix regexes also matched Claude Agent Teams. Click the catalog label (plus an optional shortcut) and repaint the stub when the PTY is sized so GOLDEN_STUB_AGENT_READY lands.
Windows WSL tab-bar launch names the new pane Terminal 2; the OSC title never arrives in 15s. Keep the Claude menu locator and stub resize repaint, and poll the terminal buffers for GOLDEN_STUB_AGENT_READY.
This was referenced Oct 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Merge-commit sync of
fork-mainwith stablyai/orcamain@ f307391. Supersedes #14 (branched from #14's head ac2d523,git merge --no-ff, no rebase).Conflict resolutions (44 conflicted files)
DesktopRelayServiceInstallerand relay-auth-identity structure. Fork behavior carried in:service.start()is fenced and never marked installed (installer);main-process-relay-startup.tsthat only re-runsinstaller.ensure()(connection backoff stays in upstream's singleRelayRetrySchedule, no double backoff);reconcileAfterBadOuterCredentialforce-refresh remint;refreshEpochreplaced by a stickyforceRefreshPendingflag so a plain reconcile that supersedes the remint still rotates the cloud session;relay-auth-coordinator-contract.ts,main-process-relay-startup.test.ts,send-agent-turn-boundary.test.ts. Removed fork-onlynotifyDesktopRelayAuthMutated/stopDesktopRelayStartupentry points; all relay auth reads go throughreadRelayAuthContext-> coordinator ->relayIdentityKey. No fork relay header/field names collide with upstream (keyExpiryDisabled,ORCA_RELAY_KEY_EXPIRY_DISABLED,onBadOuterCredentialare absent upstream).relay-auth-coordinator.tswas over max-lines: option/ownership types moved torelay-auth-coordinator-types.ts(re-exported).copyPatchValuesstays in the fork'sruntime-automation-update-value.ts(+extraAgentArgs), upstreamassertOwnerkept.launchAgentTerminaltakes both forklaunchPreferencesand upstreamextraAgentArgs; background launch routes the fork'ssessionOptionsthrough upstream'sresolveAgentStartupPlanInputs.openResumeTabstructure on upstream'spersistAgentLaunchTabOrder.pasteTextIntoTerminalPane, still returning the promise (fork callers await it).SKILL_RUNTIME_CAPABILITIES+PREFLIGHT_WORKSPACE_SCOPED_RUNTIME_CAPABILITY, fork capabilities via the tail spread.permission: 'workspace';apple-speech-sessionimportsspawnProcessfrom@orca/process-host; upstream's newAutomationEditorSettingsSidebar.test.tsxmocks the fork model field.rpc-params-catalog.generated.tsandbundled-skill-guides.ts.Automation extra args: fork
extraArgs->agentFlags--agent-flags), editor, i18n, RPC catalog. New capabilityautomation.agent-flags.v1. UpstreamextraAgentArgsand its allowlist are untouched.agentFlags(rejects model/agent/effort/permission flags).automation-agent-flags-migration.ts, wired inloaded-state-parsing.ts): one-time on load; moves legacyextraArgsontoagentFlags(never overwrites an existingagentFlags), dropsextraArgs, setsloadNeedsSave. Idempotent; never reads or writesextraAgentArgs.agentFlags(storeassertAutomationAgentFlags+ editor save toast): "Agent flags require a fresh session for every run. Turn off session reuse or clear the agent flags."launchHeadlessAutomationAgent(existing workspace vialaunchPreferences; new-per-run via the create args).e2e fixme
terminal-pane-title-strip-placement.spec.ts> "Set Title strip activates its pane and accepts file-path drops" istest.fixmeon the fork only. It fails identically upstream since stablyai#26385 (merged with this spec red); upstream's TerminalPaneHeaderOverlay unit test asserts the opposite activation contract, so the fork's 6-line fix ce52fe4 was reverted by 49b6cfc. The comment says not to retry it.Muse's 4 relay checks (run before push, all passing)
relay-auth-coordinator.test.ts> "auth-coordinator: 4401 then refresh then reconcile leaves exactly one minted broker with bounded forced reads under concurrent callers". Exposed a real gap: a plain reconcile superseding the forced remint read the unrotated session. Fixed with the sticky force-refresh flag.desktop-relay-service-installer.test.ts> "installer: a failed start is torn down, not marked installed, and the next attempt is a clean install"main-process-relay-install-retry.test.ts> "startup retry: retries install on 1/5/15/60s, separate from connection backoff, without blocking app-ready" (+ "stops retrying once a service is installed or the app is quitting")relay-session-broker.test.ts> "origin-pool: a 4401 during an in-flight drain resolution cancels the retry first and fails the revoked request fast". Exposed a real gap: in-flight drain resolution could still open a target with the revoked token. Fixed withcredentialRevoked.The fork's 503 test ("clears a scheduled retry and force-refreshes on 4401 recovery") still holds under upstream's retry timing: it asserts the fence cancels the pending retry, not a specific delay.
New automation tests:
headless-automation-agent-launch-fork-args.test.ts(model/effort/profile, agentFlags, extraAgentArgs, both together, new-per-run create, reuse-session refusal) andautomation-agent-flags-migration.test.ts.Local checks (box, via heavy-run)
tsc --noEmit(node + web on touched files) and fulltsconfig.tc.cli.json: clean.--maxWorkers=1on 295 related test files: 2313 passed, 1 skipped.mobile/tests (separate install) and the full matrix. Left to CI.