Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
89ba968
ci: keep shared unit fixture out of package and browser jobs (#26575)
nwparker Oct 8, 2026
907cb6e
ci: restore five unit runners and prune source-only tests (#26437)
nwparker Oct 8, 2026
17703d0
fix(native-chat): never refuse a user's write because the retry recor…
brennanb2025 Oct 8, 2026
51e2895
fix(native-chat): never refuse a queued card because 20 were waiting,…
brennanb2025 Oct 8, 2026
7bdb0b6
Native chat: inline visuals for Grok, OpenCode and OMP chats (#26530)
brennanb2025 Oct 8, 2026
884be9a
feat(native-chat): show each chat's resume as it happens, and start m…
brennanb2025 Oct 8, 2026
79a8cff
Fix Mermaid diagrams that stay on error after replies finish (#26480)
brennanb2025 Oct 8, 2026
cc291db
Keep picked skills and pending uploads when native chat composers clo…
brennanb2025 Oct 8, 2026
6b43714
feat(agent-sessions): rename "Continue in New Session" to "Hand Off t…
brennanb2025 Oct 8, 2026
3e27e62
Native chat: open files from tool rows through the terminal's file li…
brennanb2025 Oct 8, 2026
d997ef0
Warn on slow profile saves instead of failing them (#26447)
AmethystLiang Oct 8, 2026
b6b4d68
fix(omp): show exit 0 for a command that finished normally (#26494)
brennanb2025 Oct 8, 2026
4390860
Update README downloads badge
github-actions[bot] Oct 8, 2026
9ca9b4e
Revert Claude per-account folders (#24434, #26405) before release (#2…
Jinwoo-H Oct 8, 2026
22974c5
Default experimental native chat to structured chat (#22933)
brennanb2025 Oct 8, 2026
4b13ab6
fix(lint): move the macOS input-source probe out of app.ts (#26643)
brennanb2025 Oct 8, 2026
04ac6d6
Hold messages in the host until a chat's agent has finished starting …
brennanb2025 Oct 8, 2026
5de5391
fix(lint): move knownAgentIds out of the session host (#26648)
brennanb2025 Oct 8, 2026
a062abf
Stop native chat jumping when Codex starts a foreground command (#26503)
brennanb2025 Oct 8, 2026
47019ae
fix(editor): route zoom gestures and app zoom to the PDF viewer (#26652)
Jinwoo-H Oct 8, 2026
6ceb423
fix(native-chat): return focus to the composer after a pick (#26574)
AmoabaKelvin Oct 8, 2026
23fd5e6
fix(browser): keep the annotation composer off the element it annotat…
AmoabaKelvin Oct 8, 2026
d4acd11
fix(window): stop a covered window drawing after a phone stream, and …
Jinwoo-H Oct 8, 2026
4735ece
fix(native-chat): a /compact sent while the agent works waits in line…
brennanb2025 Oct 8, 2026
55eb48c
Let automations pass extra agent arguments on each run (#26659)
AmethystLiang Oct 8, 2026
ff4a51c
Show sign-in guidance for all native chat agents (#26544)
brennanb2025 Oct 8, 2026
58a58f4
Show OMP sign-in guidance when OMP reports no model selected (#26649)
brennanb2025 Oct 8, 2026
81fd59d
fix: keep workspace search filter button on one line (#26580)
genni613 Oct 8, 2026
4d1a3dd
Detect installed GitHub CLI behind hung launchers (#25183)
OrcaWin Oct 8, 2026
3c07588
feat(native-chat): make native chat replies flow in and the transcrip…
AmoabaKelvin Oct 8, 2026
bb44f74
Keep native chat /clear in the same conversation (#26579)
brennanb2025 Oct 8, 2026
59b9bde
Reduce repeated test work and fix Windows cleanup and IME confirmatio…
nwparker Oct 8, 2026
dec18a8
fix(runtime): settle DSH tui-idle on its hook-store done (#26481)
Jinwoo-H Oct 9, 2026
ad7af63
fix(relay): throttle the connection-reservations autovacuum so a run …
Jinwoo-H Oct 9, 2026
0e8e4e7
Reduce repeated test work and skip unrelated server matrices (#26711)
nwparker Oct 9, 2026
4ad8690
Resolve native chat workspaces from catalog snapshots (#26428)
AmethystLiang Oct 9, 2026
d010c83
test(terminal): check the runtime's workspace layout against structur…
Jinwoo-H Oct 9, 2026
7f0e067
test(e2e): layout oracle scenarios with window, headless serve and SS…
Jinwoo-H Oct 9, 2026
37833ce
feat(native-chat): add a chat-owned command receipt store (#26653)
brennanb2025 Oct 9, 2026
d191386
Offer Resume in New CLI / Native Chat from the tab right-click menu (…
brennanb2025 Oct 9, 2026
820277c
Show pre-upgrade Experimental Chat UI users a one-time native chat up…
brennanb2025 Oct 9, 2026
ebb192e
Native chat: Cmd/Ctrl+F finds in the chat (#26517)
brennanb2025 Oct 9, 2026
978c32b
fix(remote): group migrated folders under their execution host (#26535)
nwparker Oct 9, 2026
da6d632
[CI] Revert library patches introduced by test optimization (#26727)
nwparker Oct 9, 2026
04d2ccb
Default status-bar usage to Compact and explain the change once (#26726)
AmethystLiang Oct 9, 2026
bdf0d66
Provide Orca CLI on managed Linux and macOS servers (#26539)
nwparker Oct 9, 2026
1cda323
Report browser placement support from the installed provider (#26559)
nwparker Oct 9, 2026
56cdd67
fix(native-chat): read a queued message in full (#26004)
brennanb2025 Oct 9, 2026
13c9f1f
fix(floating-workspace): keep file links in their owning panel (#26655)
brennanb2025 Oct 9, 2026
8d3c922
refactor(tabs): reuse persistAgentLaunchTabOrder for copied tab-order…
brennanb2025 Oct 9, 2026
8167dda
Distinguish remote browser failures from server connection failures (…
nwparker Oct 9, 2026
b9a7830
Keep new browser tabs on SSH routing after managed conversion (#26570)
nwparker Oct 9, 2026
118de20
Keep open Remote Settings subscribed to the saved-server catalog (#26…
nwparker Oct 9, 2026
b71e538
Explain why stopping the selected Active Server is refused (#26584)
nwparker Oct 9, 2026
6a15cd8
Preserve editor file identity during SSH host conversion (#26593)
nwparker Oct 9, 2026
4e232f9
Preserve execution host identity throughout folder sidebar rows (#26634)
nwparker Oct 9, 2026
f3c0390
Fix Compact usage notice focus and older-host compatibility (#26747)
AmethystLiang Oct 9, 2026
45a969f
Wait for retained editor ownership before listing Markdown documents …
nwparker Oct 9, 2026
5264a7d
Retire canceled managed startup checks before reconnecting (#26645)
nwparker Oct 9, 2026
b79862d
Describe unverifiable managed servers without claiming they stopped (…
nwparker Oct 9, 2026
d2d2d39
Refresh rich Markdown links when document metadata changes (#26595)
nwparker Oct 9, 2026
496a171
fix(acp): keep OMP replies that follow its reasoning (#26658)
brennanb2025 Oct 9, 2026
6235f9a
fix(acp): show the agent's own reason when a prompt fails (#26666)
brennanb2025 Oct 9, 2026
f9d0aa2
Refresh open Markdown links when workspace files change (#26599)
nwparker Oct 9, 2026
4f126bc
Show "Pi isn't signed in" in native chat before the first send (#26743)
brennanb2025 Oct 9, 2026
d273d85
fix(native-chat): underline a file path only once its workspace confi…
brennanb2025 Oct 9, 2026
55d348d
feat(native-chat): show an agent message's sender by its current titl…
brennanb2025 Oct 9, 2026
fc5eb16
Send a headless automation's prompt to agents that read it after they…
brennanb2025 Oct 9, 2026
d7e985c
Start worktree.create's agent through the launch executor (#26709)
brennanb2025 Oct 9, 2026
46460d4
feat(runtime): require Node 24 for servers and remote hosts (#26171)
nwparker Oct 9, 2026
db53143
Update README downloads badge
github-actions[bot] Oct 9, 2026
ded0144
fix(native-chat): settle a dead agent's leftover work in one write th…
brennanb2025 Oct 9, 2026
f01bd93
Keep managed workspace paths out of desktop editor launches (#26668)
nwparker Oct 9, 2026
cf8cc09
[CI] Enable the existing Windows hang watchdog and preserve restart e…
nwparker Oct 9, 2026
cc2ad7b
fix: dispatch Muse Windows hooks directly on safe profile paths (#26755)
nwparker Oct 9, 2026
69cf557
fix(sidebar): keep project headers from overlapping the pinned host (…
AmethystLiang Oct 9, 2026
cbad641
feat(grok): show Grok's subagents as subagent rows (#26508)
brennanb2025 Oct 9, 2026
bfd9858
Retry failed catalog reads when SSH hosts move to Remote (#26531)
nwparker Oct 9, 2026
418c601
Start orchestration workers and remote workers through the launch exe…
brennanb2025 Oct 9, 2026
bcb7305
Refresh SSH host status after a verified manual managed-server update…
nwparker Oct 9, 2026
c586cce
fix(acp): start chats for agents that report no model (#26587)
brennanb2025 Oct 9, 2026
4eb6c0e
test(native-chat): fix main typecheck after the batched journal commi…
brennanb2025 Oct 9, 2026
df922d3
Keep one local project identity after concurrent registration (#26789)
nwparker Oct 9, 2026
6ef42ad
Keep Git identity probes from blocking SSH host reconversion (#26578)
nwparker Oct 9, 2026
6ba8641
Show model and effort choices for every agent before its session star…
brennanb2025 Oct 9, 2026
39a01f9
feat(agent-launch): create a folder workspace and start its agent in …
brennanb2025 Oct 9, 2026
1578716
revert(runtime): temporarily restore the previous host Node minimum (…
nwparker Oct 9, 2026
3ca1d81
fix(source-control): wait for the repo owner's editor saves before di…
nwparker Oct 9, 2026
fd6bc7e
Keep managed status warnings out of desktop gitignore writes (#26671)
nwparker Oct 9, 2026
e43997c
Roll back Windows hang watchdog activation (#26804)
nwparker Oct 9, 2026
2c0a24f
Merge remote-tracking branch 'origin/main' into OrcaWin/phase37-sync1
Oct 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions .github/workflows/computer-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ on:
- 'electron.vite.config.ts'
- 'config/build-plugins/**'
- 'src/main/daemon/**'
- '!src/main/daemon/**/*.test.ts'
- 'src/main/providers/local-pty-provider.ts'
- 'src/main/providers/windows-shell-args.ts'
- 'src/main/providers/windows-shell-preflight-runtime.windows.test.ts'
Expand Down
36 changes: 30 additions & 6 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -342,13 +342,23 @@ jobs:
. != "tests/e2e/terminal-retention-budget.spec.ts" and
. != "tests/e2e/ssh-startup-exec-readiness.spec.ts" and
. != "tests/e2e/paired-startup-exec-readiness.spec.ts" and
. != "tests/e2e/workspace-layout-oracle-ssh.spec.ts" and
. != "tests/e2e/ssh-browser-network-execution-route.docker.unit.test.ts" and
. != "tests/e2e/ssh-localhost.spec.ts" and
. != "tests/e2e/terminal-ibus-hangul-native.spec.ts" and
. != "tests/e2e/orcad-serve-mode-switch.spec.ts" and
. != "tests/e2e/workspace-layout-oracle-headless.spec.ts" and
. != "tests/e2e/ssh-orcad-auto-convert.spec.ts" and
. != "tests/e2e/windows-missing-appdata-startup.spec.ts" and
. != "tests/e2e/ssh-orcad-idle-exit.spec.ts"
. != "tests/e2e/ssh-orcad-idle-exit.spec.ts" and
. != "tests/e2e/ssh-orcad-browser-capabilities.spec.ts" and
. != "tests/e2e/ssh-orcad-browser-service-status.spec.ts" and
. != "tests/e2e/ssh-orcad-browser-routing.spec.ts" and
. != "tests/e2e/ssh-orcad-editor-ownership.spec.ts" and
. != "tests/e2e/ssh-orcad-markdown-conversion.spec.ts" and
. != "tests/e2e/ssh-orcad-markdown-link-refresh.spec.ts" and
. != "tests/e2e/ssh-orcad-markdown-live-documents.spec.ts" and
. != "tests/e2e/ssh-orcad-open-in-owner.spec.ts"
)' <<<"$TEST_FILES_JSON" > "$RUNNER_TEMP/general-e2e-specs"
fi
mapfile -t TEST_FILES < "$RUNNER_TEMP/general-e2e-specs"
Expand Down Expand Up @@ -417,7 +427,8 @@ jobs:
contains(inputs.test_files, 'tests/e2e/ssh-terminal-parking.spec.ts') ||
contains(inputs.test_files, 'tests/e2e/terminal-retention-budget.spec.ts') ||
contains(inputs.test_files, 'tests/e2e/ssh-startup-exec-readiness.spec.ts') ||
contains(inputs.test_files, 'tests/e2e/paired-startup-exec-readiness.spec.ts')
contains(inputs.test_files, 'tests/e2e/paired-startup-exec-readiness.spec.ts') ||
contains(inputs.test_files, 'tests/e2e/workspace-layout-oracle-ssh.spec.ts')
runs-on: ubuntu-latest
strategy:
fail-fast: false
Expand Down Expand Up @@ -520,9 +531,12 @@ jobs:
orcad-serve-mode-switch:
name: orca serve Electron/orcad mode switch (D7)
needs: [build, prepare-native-cache]
if: inputs.test_files == '' || contains(inputs.test_files, 'tests/e2e/orcad-serve-mode-switch.spec.ts')
if: >-
inputs.test_files == '' ||
contains(inputs.test_files, 'tests/e2e/orcad-serve-mode-switch.spec.ts') ||
contains(inputs.test_files, 'tests/e2e/workspace-layout-oracle-headless.spec.ts')
runs-on: ubuntu-latest
timeout-minutes: 30
timeout-minutes: 45
env:
ORCA_BACKGROUND_LAUNCH: '1'
steps:
Expand All @@ -549,11 +563,21 @@ jobs:
pnpm build:orcad
node config/scripts/build-orcad-template.mjs --targets "$slot"
- name: Switch serve hosts on one profile
if: inputs.test_files == '' || contains(inputs.test_files, 'tests/e2e/orcad-serve-mode-switch.spec.ts')
env:
SKIP_BUILD: '1'
ORCA_E2E_ORCAD_SERVE: '1'
ORCA_E2E_FORWARD_APP_LOGS: '1'
run: xvfb-run --auto-servernum bash .github/scripts/e2e-with-window-manager.sh pnpm exec playwright test --config tests/playwright.config.ts tests/e2e/orcad-serve-mode-switch.spec.ts --project=electron-headless --workers=1
# The layout oracle's headless scenarios run on both serve hosts, so they need this job's orcad.
- name: Layout oracle on headless serve (orcad and Electron)
if: >-
!cancelled() &&
(inputs.test_files == '' || contains(inputs.test_files, 'tests/e2e/workspace-layout-oracle-headless.spec.ts'))
env:
SKIP_BUILD: '1'
ORCA_E2E_FORWARD_APP_LOGS: '1'
run: xvfb-run --auto-servernum bash .github/scripts/e2e-with-window-manager.sh pnpm exec playwright test --config tests/playwright.config.ts tests/e2e/workspace-layout-oracle-headless.spec.ts --project=electron-headless --workers=1
- uses: actions/upload-artifact@v7
if: failure()
with:
Expand All @@ -568,7 +592,7 @@ jobs:
orcad-auto-convert-docker:
name: ssh host auto-converts to managed orcad (Docker)
needs: [build, prepare-native-cache]
if: inputs.test_files == '' || contains(inputs.test_files, 'tests/e2e/ssh-orcad-auto-convert.spec.ts') || contains(inputs.test_files, 'tests/e2e/ssh-orcad-idle-exit.spec.ts')
if: inputs.test_files == '' || contains(inputs.test_files, 'tests/e2e/ssh-orcad-auto-convert.spec.ts') || contains(inputs.test_files, 'tests/e2e/ssh-orcad-idle-exit.spec.ts') || contains(inputs.test_files, 'tests/e2e/ssh-orcad-browser-capabilities.spec.ts') || contains(inputs.test_files, 'tests/e2e/ssh-orcad-browser-service-status.spec.ts') || contains(inputs.test_files, 'tests/e2e/ssh-orcad-browser-routing.spec.ts') || contains(inputs.test_files, 'tests/e2e/ssh-orcad-editor-ownership.spec.ts') || contains(inputs.test_files, 'tests/e2e/ssh-orcad-markdown-conversion.spec.ts') || contains(inputs.test_files, 'tests/e2e/ssh-orcad-markdown-link-refresh.spec.ts') || contains(inputs.test_files, 'tests/e2e/ssh-orcad-markdown-live-documents.spec.ts') || contains(inputs.test_files, 'tests/e2e/ssh-orcad-open-in-owner.spec.ts')
runs-on: ubuntu-latest
timeout-minutes: 45
env:
Expand Down Expand Up @@ -604,7 +628,7 @@ jobs:
ORCA_RELAY_PATH: ${{ github.workspace }}/out/relay
run: |
export ORCA_E2E_ORCAD_CONVERT_TEMPLATE="$RUNNER_TEMP/orcad-convert-template"
xvfb-run --auto-servernum bash .github/scripts/e2e-with-window-manager.sh pnpm exec playwright test --config tests/playwright.config.ts tests/e2e/ssh-orcad-auto-convert.spec.ts tests/e2e/ssh-orcad-idle-exit.spec.ts --project=electron-headless --workers=1
xvfb-run --auto-servernum bash .github/scripts/e2e-with-window-manager.sh pnpm exec playwright test --config tests/playwright.config.ts tests/e2e/ssh-orcad-auto-convert.spec.ts tests/e2e/ssh-orcad-idle-exit.spec.ts tests/e2e/ssh-orcad-browser-capabilities.spec.ts tests/e2e/ssh-orcad-browser-service-status.spec.ts tests/e2e/ssh-orcad-browser-routing.spec.ts tests/e2e/ssh-orcad-editor-ownership.spec.ts tests/e2e/ssh-orcad-markdown-conversion.spec.ts tests/e2e/ssh-orcad-markdown-link-refresh.spec.ts tests/e2e/ssh-orcad-markdown-live-documents.spec.ts tests/e2e/ssh-orcad-open-in-owner.spec.ts --project=electron-headless --workers=1
- uses: actions/upload-artifact@v7
if: failure()
with:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/pi-owner-runtime.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ on:
pull_request:
paths:
- 'src/main/pi/**'
- '!src/main/pi/**/*.test.ts'
- 'tests/tools/pi-owner-runtime-smoke.mjs'
- 'tests/tools/omp-completion-runtime-smoke.mjs'
- '.github/workflows/pi-owner-runtime.yml'
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -432,8 +432,8 @@ jobs:
PREFLIGHT_PHASE_SELECTED: ${{ needs.code_paths.outputs.typecheck == 'true' }}
PREFLIGHT_PRIOR_SUCCESS: ${{ job.status == 'success' }}
ORCA_UNIT_SELECTION_MODE: ${{ vars.ORCA_UNIT_SELECTION_MODE || 'shadow' }}
# Set the repository variable to '5' to roll back full PR shards.
ORCA_UNIT_FULL_SHARD_COUNT: ${{ vars.ORCA_UNIT_FULL_SHARD_COUNT || '10' }}
# Five shards use fewer runner minutes; the repository variable can still request ten.
ORCA_UNIT_FULL_SHARD_COUNT: ${{ vars.ORCA_UNIT_FULL_SHARD_COUNT || '5' }}
run: |
if [ "$PREFLIGHT_PHASE_SELECTED" != true ] || [ "$PREFLIGHT_PRIOR_SUCCESS" != true ]; then exit 0; fi
node config/scripts/ci-unit-plan.mjs
Expand Down Expand Up @@ -1275,7 +1275,6 @@ jobs:
src/main/wsl/wsl-runner.test.ts
src/main/wsl/wsl-guest-environment.test.ts
src/main/wsl/wsl-executable-path.win32.test.ts
src/main/claude-accounts/claude-profile-history-windows.test.ts
src/main/wsl/wsl-w1-w3-contract.test.ts
src/shared/source-scan/source-tree-scan.test.ts
src/main/cli/wsl-cli-powershell-boundary.test.ts
Expand All @@ -1296,6 +1295,7 @@ jobs:
src/relay/windows-port-scan.win32.test.ts
src/main/ssh/ssh-relay-upload-stage-windows-identity.test.ts
src/main/ssh/remote-node-runtime-store-windows.test.ts
config/scripts/node-pty-windows-pty-teardown-patch.test.mjs

# Why the :parallel variant: identical to build:release except the three
# electron-vite targets overlap instead of running back to back. The Linux package
Expand Down
58 changes: 58 additions & 0 deletions .github/workflows/preflight-cli-platforms.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: Preflight CLI platforms

on:
pull_request:
paths:
- 'src/main/ipc/preflight*'
- 'src/main/ipc/agent-detection-shell-path.ts'
- 'src/main/ipc/command-path-resolver*'
- 'src/main/preflight/**'
- 'src/main/startup/*shell*'
- 'src/shared/child-process/**'
- '.github/actions/install-node-dependencies/**'
- '.github/workflows/preflight-cli-platforms.yml'
workflow_dispatch:

permissions:
contents: read

concurrency:
group: preflight-cli-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
preflight:
name: Preflight CLI (${{ matrix.os }})
runs-on: ${{ matrix.os }}
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
os: [ubuntu-22.04, macos-15, windows-2022]
env:
ORCA_BACKGROUND_LAUNCH: '1'
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: ./.github/actions/install-node-dependencies
with:
native-runtime: node
cache-electron-package: 'true'
- name: Check native CLI execution and shell PATH discovery
run: >-
pnpm exec vitest run --config config/vitest.config.ts --maxWorkers=2
src/main/ipc/preflight-command-exec.test.ts
src/main/ipc/preflight-host-cli-status.test.ts
src/main/ipc/preflight-runnable-local-cli.test.ts
src/main/ipc/preflight-agent-detection.test.ts
src/main/ipc/preflight-agent-refresh.test.ts
src/main/ipc/preflight-wsl-agent-detection.test.ts
src/main/ipc/preflight-windows-path-refresh.repro.test.ts
src/main/startup/hydrate-shell-path.test.ts
src/main/startup/hydrate-shell-path.windows.test.ts
src/main/startup/login-shell-environment.test.ts
src/main/runtime/rpc/methods/preflight.test.ts
src/shared/child-process/process-tree-termination.test.ts
src/shared/child-process/run-process.test.ts
src/shared/child-process/run-process-termination-failure.test.ts
1 change: 1 addition & 0 deletions .github/workflows/win-orcad-serve-switch-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ on:
types: [opened, synchronize, reopened, ready_for_review]
paths:
- 'src/main/daemon/**'
- '!src/main/daemon/**/*.test.ts'
- 'src/main/orcad/**'
- 'src/cli/runtime/**'
- 'src/shared/orcad-local-serve-selection.ts'
Expand Down
28 changes: 28 additions & 0 deletions .oxlintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,34 @@
"unicorn/throw-new-error": "error"
},
"overrides": [
{
"files": ["**/*.{js,cjs,mjs,jsx,ts,tsx,mts,cts}"],
"excludeFiles": [
"**/*.{test,spec}.{js,cjs,mjs,jsx,ts,tsx,mts,cts}",
"**/__tests__/**",
"src/renderer/src/runtime/web-runtime-browser-creation-placement-test-rig.ts"
],
"rules": {
"no-restricted-imports": [
"error",
{
"paths": [
{
"name": "@linear/sdk",
"allowTypeImports": true,
"message": "Value-importing @linear/sdk hoists its ~2.6MB CJS bundle into the eager top-level require block and defeats the lazy loader. Use `import type` plus loadLinearSdk() from src/main/linear/linear-sdk.ts."
}
],
"patterns": [
{
"regex": "(?i)(?:^|[/\\\\])(?:web-session-tabs-sync-test-harness|web-runtime-browser-creation-placement-test-rig)(?:\\.[cm]?[jt]sx?)?(?:[?#].*)?$",
"message": "This module is unit-test support. Import the production web-session owner instead."
}
]
}
]
}
},
{
"files": ["src/renderer/src/**/*.{ts,tsx}"],
"rules": {
Expand Down
9 changes: 8 additions & 1 deletion cloud/apps/relay/src/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -706,7 +706,14 @@ export const POSTGRES_SCHEMA_MIGRATIONS = [
// Deferrable for the same reason, though SHARE UPDATE EXCLUSIVE blocks only vacuum and DDL: it
// buys nothing until the drop lands, so a boot that deferred the drop should defer this too.
`-- schema-deferrable: buys nothing until the drop above lands
ALTER TABLE relay_assignment_activity_leases SET (fillfactor = 70)`
ALTER TABLE relay_assignment_activity_leases SET (fillfactor = 70)`,
// Why: each reservations autovacuum read its ~5.5 GB of indexes in ~3 min, about hourly, evicting
// the cache of the Cloud SQL instance shared with auth. 20 ms per 200 cost units spreads a run
// over ~15 min. Deferrable: a running vacuum holds the same lock, and nothing at boot needs this.
`-- schema-deferrable: a running vacuum holds the lock this needs
ALTER TABLE relay_control_connection_reservations SET (autovacuum_vacuum_cost_delay = 20)`,
`-- schema-deferrable: a running vacuum holds the lock this needs
ALTER TABLE relay_control_connection_reservations SET (autovacuum_vacuum_cost_limit = 200)`
]

// The exact statement list a Postgres boot applies, in order, so the lock-target census can read
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,47 @@ describePostgres('relay boot-time schema against PostgreSQL', () => {
}
})

it('throttles the reservations vacuum, deferring it while a vacuum holds the table', async () => {
const reservationOptions = async (): Promise<unknown> =>
(
await pool.query(`SELECT reloptions FROM pg_class WHERE oid = to_regclass($1)`, [
`${schema}.${LOCKED_TABLE}`
])
).rows[0]?.reloptions
const cold = await openRelayDatabase({ databaseUrl: url, dataDir: '' })
opened.push(cold)
expect(await reservationOptions()).toEqual([
'autovacuum_vacuum_cost_delay=20',
'autovacuum_vacuum_cost_limit=200'
])
await pool.query(
`ALTER TABLE ${schema}.${LOCKED_TABLE}
RESET (autovacuum_vacuum_cost_delay, autovacuum_vacuum_cost_limit)`
)

// The lock a running (auto)vacuum holds; the boot must yield to it rather than fail.
const holder = new pg.Client({ connectionString: url })
await holder.connect()
await holder.query('BEGIN')
await holder.query(`LOCK TABLE ${LOCKED_TABLE} IN SHARE UPDATE EXCLUSIVE MODE`)
try {
const behindVacuum = await openRelayDatabase({ databaseUrl: url, dataDir: '' })
opened.push(behindVacuum)
} finally {
await holder.query('ROLLBACK')
await holder.end()
}
expect(await reservationOptions()).toBeNull()

const next = await openRelayDatabase({ databaseUrl: url, dataDir: '' })
opened.push(next)
expect(await reservationOptions()).toEqual([
'autovacuum_vacuum_cost_delay=20',
'autovacuum_vacuum_cost_limit=200'
])
await pool.end()
})

it('defers the activity-lease migrations and still boots while their table is locked', async () => {
// The migration boot, reproduced: the index is there, the table is locked by someone else, and
// all the drop can do is time out. It has to leave the statement for the next boot rather than
Expand Down
18 changes: 16 additions & 2 deletions cloud/apps/relay/src/relay-schema-lock-targets.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,18 @@ const GOLDEN_LOCK_TAKING: SchemaLockTarget[] = [
table: 'relay_assignment_activity_leases',
name: 'fillfactor=70',
skipWhen: 'present'
},
{
kind: 'reloption',
table: 'relay_control_connection_reservations',
name: 'autovacuum_vacuum_cost_delay=20',
skipWhen: 'present'
},
{
kind: 'reloption',
table: 'relay_control_connection_reservations',
name: 'autovacuum_vacuum_cost_limit=200',
skipWhen: 'present'
}
]

Expand Down Expand Up @@ -240,7 +252,7 @@ describe('relay boot-time lock targets', () => {
}
})

it('marks the out-of-band sweep indexes and the activity-lease migrations deferrable, and nothing else', () => {
it('marks the out-of-band sweep indexes, the activity-lease migrations and the reservation vacuum throttle deferrable, and nothing else', () => {
// The statements a lock timeout must not turn into a crash loop, and the only ones: every
// other statement still fails the boot loudly, which is what keeps the marker meaningful.
const deferrable = relayPostgresSchemaStatements().filter(schemaDeferrable)
Expand All @@ -250,7 +262,9 @@ describe('relay boot-time lock targets', () => {
'CREATE INDEX IF NOT EXISTS relay_direct_authorizations_pending_deadline ON relay_direct_authorizations(deadline) WHERE consumed_at IS NULL',
'CREATE INDEX IF NOT EXISTS relay_rate_windows_started ON relay_rate_windows(window_started_at)',
'DROP INDEX IF EXISTS relay_assignment_activity_expiry',
'ALTER TABLE relay_assignment_activity_leases SET (fillfactor = 70)'
'ALTER TABLE relay_assignment_activity_leases SET (fillfactor = 70)',
'ALTER TABLE relay_control_connection_reservations SET (autovacuum_vacuum_cost_delay = 20)',
'ALTER TABLE relay_control_connection_reservations SET (autovacuum_vacuum_cost_limit = 200)'
])
})

Expand Down
Loading
Loading