diff --git a/src/main/automations/observation/retained-run-reconciliation.test.ts b/src/main/automations/observation/retained-run-reconciliation.test.ts index 00d49902084..4f9a93e2695 100644 --- a/src/main/automations/observation/retained-run-reconciliation.test.ts +++ b/src/main/automations/observation/retained-run-reconciliation.test.ts @@ -41,8 +41,6 @@ const LAUNCH_TARGET = { const OPEN_LAUNCHER = { launch: async () => ({ ...LAUNCH_TARGET }), available: () => true } -const AFTER_SETTLE_MS = 10 * 60 * 1000 - function createAutomation(store: TestStore): Automation { store.addRepo(makeRepo()) return store.createAutomation({ @@ -117,24 +115,6 @@ describe('reconciling retained runs against a graph that has not published yet', rmSync(testState.dir, { recursive: true, force: true }) }) - it('does not fail a desktop-startup retained run while the window graph is empty', async () => { - const store = await createStore() - const automation = createAutomation(store) - const retained = retainDispatchedRun(store, automation) - const surface = createPaneSurface() - const service = new AutomationService(store, { - terminalObserver: surface.observer, - terminalLauncher: { launch: async () => ({ ...LAUNCH_TARGET }), available: () => false } - }) - - service.start() - await vi.advanceTimersByTimeAsync(AFTER_SETTLE_MS) - - expect(readRun(store, automation.id, retained.id).status).toBe('dispatched') - expect(readRun(store, automation.id, retained.id).error).toBeNull() - service.stop() - }) - it('re-attaches to the run once the restored pane mounts seconds later', async () => { const store = await createStore() const automation = createAutomation(store) diff --git a/src/main/automations/ownership/automation-ssh-readoption-migration.test.ts b/src/main/automations/ownership/automation-ssh-readoption-migration.test.ts deleted file mode 100644 index 88325f956c0..00000000000 --- a/src/main/automations/ownership/automation-ssh-readoption-migration.test.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { describe, it, expect } from 'vitest' -import { - migrateAutomationHostFilterSshTargetId, - migrateAutomationsForSshReadoption -} from './automation-ssh-readoption-migration' -import { hostStableKey } from '../../../shared/automations/ownership/automation-owner-key' -import type { Automation } from '../../../shared/automations/automation-definition' -import type { AutomationRun } from '../../../shared/automations/history/automation-run' -import type { PersistedUIState } from '../../../shared/persisted-ui-state-types' - -const NOW = 1_700_000_000_000 -const OLD_ID = 'ssh-1738-a9f3x' -const NEW_ID = 'ssh-1799-b2k7z' - -function makeAutomation(overrides: Partial = {}): Automation { - return { - id: 'auto-1', - name: 'Nightly', - prompt: 'go', - precheck: null, - agentId: 'codex', - projectId: 'repo-1', - executionTargetType: 'ssh', - executionTargetId: OLD_ID, - executionTargetGeneration: 3, - schedulerOwner: 'local_host_service', - workspaceMode: 'new_per_run', - workspaceId: null, - baseBranch: null, - reuseSession: false, - timezone: 'UTC', - rrule: 'FREQ=DAILY', - dtstart: NOW, - enabled: true, - nextRunAt: NOW, - missedRunPolicy: 'run_once_within_grace', - missedRunGraceMinutes: 720, - createdAt: NOW, - updatedAt: NOW, - ...overrides - } -} - -function migrate( - automations: Automation[], - generation: number | undefined, - runs: AutomationRun[] = [] -) { - return migrateAutomationsForSshReadoption({ - automations, - automationRuns: runs, - oldTargetId: OLD_ID, - newTargetId: NEW_ID, - newTargetGeneration: generation - }) -} - -function runContext(hostId: string) { - return { - kind: 'workspace-run' as const, - projectId: 'project-1', - hostId: hostId as `ssh:${string}`, - projectHostSetupId: 'setup-1', - repoId: 'repo-1', - path: '/srv/repo' - } -} - -function uiWithFilter(hostKey: string): PersistedUIState { - return { automationHostFilter: { kind: 'host', hostKey } } as PersistedUIState -} - -describe('migrateAutomationsForSshReadoption', () => { - it('re-points the owner and adopts the re-added registration generation', () => { - const automation = makeAutomation() - expect(migrate([automation], 9)).toBe(true) - expect(automation.executionTargetId).toBe(NEW_ID) - expect(automation.executionTargetGeneration).toBe(9) - }) - - it('drops a stale capture when the re-added target carries no generation', () => { - const automation = makeAutomation() - expect(migrate([automation], undefined)).toBe(true) - expect(automation.executionTargetId).toBe(NEW_ID) - expect('executionTargetGeneration' in automation).toBe(false) - }) - - it('migrates run and source context host ids, including for local records', () => { - const automation = makeAutomation({ - executionTargetType: 'local', - executionTargetId: 'local', - executionTargetGeneration: undefined, - runContext: runContext(`ssh:${OLD_ID}`), - sourceContext: { - kind: 'task-source', - provider: 'github', - projectId: 'project-1', - hostId: `ssh:${OLD_ID}` - } - }) - expect(migrate([automation], 9)).toBe(true) - expect(automation.runContext?.hostId).toBe(`ssh:${NEW_ID}`) - expect(automation.sourceContext?.hostId).toBe(`ssh:${NEW_ID}`) - expect(automation.executionTargetId).toBe('local') - expect(automation.executionTargetGeneration).toBeUndefined() - }) - - it('re-points run history so workspace navigation survives re-adoption', () => { - const run = { - id: 'run-1', - automationId: 'auto-1', - runContext: runContext(`ssh:${OLD_ID}`) - } as AutomationRun - expect(migrate([], 9, [run])).toBe(true) - expect(run.runContext?.hostId).toBe(`ssh:${NEW_ID}`) - }) -}) - -describe('migrateAutomationHostFilterSshTargetId', () => { - it('never rewrites a runtime authority filter that reuses the same target id', () => { - const hostKey = hostStableKey({ - authority: { kind: 'runtime', environmentId: 'env-1' }, - selector: { kind: 'ssh', targetId: OLD_ID } - }) - const ui = uiWithFilter(hostKey) - expect(migrateAutomationHostFilterSshTargetId(ui, OLD_ID, NEW_ID)).toBe(false) - expect(ui.automationHostFilter).toEqual({ kind: 'host', hostKey }) - }) -}) diff --git a/src/main/runtime/rpc/methods/orchestration/worker/release/worker-release-archive.spec.ts b/src/main/runtime/rpc/methods/orchestration/worker/release/worker-release-archive.spec.ts index b2c662090c8..ac67fe66629 100644 --- a/src/main/runtime/rpc/methods/orchestration/worker/release/worker-release-archive.spec.ts +++ b/src/main/runtime/rpc/methods/orchestration/worker/release/worker-release-archive.spec.ts @@ -75,84 +75,5 @@ export function registerWorkerReleaseArchiveTests(): void { await rm(directory, { recursive: true, force: true }) } }) - - it('preserves payload clipping metadata in the released transcript snapshot', async () => { - h.setup() - const directory = await mkdtemp(join(tmpdir(), 'orca-worker-release-clipped-snapshot-')) - const transcriptPath = join(directory, 'rollout.jsonl') - try { - await writeFile( - transcriptPath, - `${JSON.stringify({ - timestamp: '2026-08-03T12:00:00.000Z', - type: 'event_msg', - payload: { id: 'clipped-message', type: 'agent_message', message: 'x'.repeat(5_000) } - })}\n` - ) - vi.mocked(h.runtime.getExactWorkerProviderSession).mockReturnValue({ - agent: 'codex', - processIncarnation: 'runtime_test:term_worker:1', - providerSession: { - key: 'codex:clipped-session', - id: 'clipped-session', - transcriptPath - } - } as never) - const { dispatchId } = await h.startSettledWorker() - await h.call('orchestration.workerRelease', { dispatch: dispatchId }) - - const read = (await h.call('orchestration.workerRead', { dispatch: dispatchId })) as { - transcript: { limited: boolean } - cursor: string - contentComplete: boolean - clipping: string[] - warnings: string[] - } - - expect(read).toMatchObject({ - transcript: { limited: true }, - contentComplete: false, - clipping: ['transcript_payload'], - warnings: ['Oversized transcript text was clipped.'] - }) - expect(read.cursor).toMatch(/^owr1_/) - expect(read.warnings).not.toContain( - 'Older transcript messages were omitted from the bounded archive.' - ) - } finally { - await rm(directory, { recursive: true, force: true }) - } - }) - - it('recovers archive metadata when a prior attempt committed only the archive row', async () => { - h.setup() - const { dispatchId } = await h.startSettledWorker() - const requested = h.db.requestWorkerTerminalRelease(dispatchId) - expect(requested.disposition).toBe('requested') - if (requested.disposition !== 'requested') { - throw new Error('release request was not recorded') - } - h.db.storeWorkerTerminalArchive({ - dispatchId, - resourceId: requested.resource.id, - kind: 'terminal_tail', - content: JSON.stringify({ - lines: ['archive survived the interrupted attempt'], - truncated: false, - terminalStatus: 'running', - warnings: [] - }) - }) - - const release = (await h.call('orchestration.workerRelease', { dispatch: dispatchId })) as { - archive: { source: string | null; status: string | null } | null - } - - expect(release.archive).toEqual({ source: 'terminal', status: 'captured' }) - expect(h.db.getWorkerTerminalResourceByOwner(dispatchId)).toMatchObject({ - archive_source: 'terminal', - archive_status: 'captured' - }) - }) }) } diff --git a/src/main/runtime/rpc/methods/orchestration/worker/release/worker-release-inventory.spec.ts b/src/main/runtime/rpc/methods/orchestration/worker/release/worker-release-inventory.spec.ts index 3897f75332a..1cf936f4d1a 100644 --- a/src/main/runtime/rpc/methods/orchestration/worker/release/worker-release-inventory.spec.ts +++ b/src/main/runtime/rpc/methods/orchestration/worker/release/worker-release-inventory.spec.ts @@ -27,27 +27,5 @@ export function registerWorkerReleaseInventoryTests(): void { ).resolves.toMatchObject({ state: 'released' }) expect(h.runtime.closeTerminal).toHaveBeenCalledTimes(1) }) - - it('reports abandoned workers as retained instead of reclaimable', async () => { - h.setup() - const { dispatchId } = await h.startWorker() - await h.call('orchestration.workerAbandon', { dispatch: dispatchId }) - - const listed = (await h.call('orchestration.workerList', { run: h.activeRunId })) as { - workers: { dispatchId: string; terminalState: string | null }[] - } - - expect(listed.workers).toContainEqual( - expect.objectContaining({ dispatchId, terminalState: 'retained' }) - ) - await expect( - h.call('orchestration.workerRelease', { dispatch: dispatchId }) - ).resolves.toMatchObject({ - state: 'retained', - reason: 'identity_unproven', - processAction: 'none' - }) - expect(h.runtime.closeTerminal).not.toHaveBeenCalled() - }) }) } diff --git a/src/main/runtime/rpc/methods/orchestration/worker/release/worker-release-mobile-report.test.ts b/src/main/runtime/rpc/methods/orchestration/worker/release/worker-release-mobile-report.test.ts index e3713c98408..15258350c4d 100644 --- a/src/main/runtime/rpc/methods/orchestration/worker/release/worker-release-mobile-report.test.ts +++ b/src/main/runtime/rpc/methods/orchestration/worker/release/worker-release-mobile-report.test.ts @@ -7,58 +7,6 @@ const h = createOrchestrationWorkerReleaseHarness() beforeEach(() => h.setup()) afterEach(() => h.cleanup()) -it.each(['local', 'ssh'])( - 'a handle-addressed phone Keep open fences %s worker release', - async (host) => { - if (host === 'ssh') { - vi.mocked(h.runtime.getOrchestrationDispatchAuthority).mockImplementation((handle) => - handle === 'term_worker' - ? ({ - terminalHandle: handle, - paneKey: h.workerPaneKey, - processIncarnation: 'runtime_test:term_worker:1', - hostScope: { kind: 'ssh', targetId: 'ssh-1' } - } as never) - : null - ) - } - const worker = await h.startSettledWorker() - expect(h.db.getWorkerTerminalResourceByOwner(worker.dispatchId)?.host_scope).toContain(host) - h.runtime.registerPreAllocatedHandleForPty('pty-worker', 'term_worker') - registerBoundPty(h.runtime, 'pty-worker', 'repo::worktree', null, { - tabId: 'tab_worker', - leafId: 'bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb' - }) - vi.mocked(h.runtime.getTerminalPaneKey).mockRestore() - await expect( - h.call('orchestration.workerKeepOpen', { terminal: 'term_worker', keep: true }) - ).resolves.toEqual({ autoClose: { kept: true } }) - await expect( - h.call('orchestration.workerRelease', { dispatch: worker.dispatchId }) - ).resolves.toMatchObject({ state: 'retained', reason: 'user_kept' }) - expect(h.runtime.closeTerminal).not.toHaveBeenCalled() - } -) - -it('an unknown handle does not fence another worker or access the database', async () => { - const worker = await h.startSettledWorker() - h.runtime.registerPreAllocatedHandleForPty('pty-worker', 'term_worker') - registerBoundPty(h.runtime, 'pty-worker', 'repo::worktree', null, { - tabId: 'tab_worker', - leafId: 'bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb' - }) - vi.mocked(h.runtime.getTerminalPaneKey).mockRestore() - const db = vi.spyOn(h.runtime, 'getOrchestrationDb') - await expect( - h.call('orchestration.workerKeepOpen', { terminal: 'term_missing', keep: true }) - ).resolves.toEqual({ autoClose: null }) - expect(db).not.toHaveBeenCalled() - expect(h.db.getWorkerTerminalResourceByOwner(worker.dispatchId)?.ownership_state).toBe('owned') - await expect( - h.call('orchestration.workerRelease', { dispatch: worker.dispatchId }) - ).resolves.toMatchObject({ state: 'released' }) -}) - // Boot-wait Keep open must find custody written at terminal creation, or a later release closes a kept pane (#19337, #19608). it('a phone Keep open during the boot wait keeps the pane and fences the later release', async () => { const gate = h.deferred()